├── .gitignore ├── .travis.yml ├── LICENSE ├── Makefile ├── README.md ├── include ├── data-types.lfe └── options.lfe ├── priv ├── images │ ├── complex-function-crop-x1000.png │ ├── complex-function-crop-x250.png │ ├── complex-function-crop-x500.png │ └── complex-function-crop.png └── make │ ├── code.mk │ └── docs.mk ├── rebar.config ├── src ├── cmplx-util.lfe ├── complex.app.src └── complex.lfe └── test ├── unit-cmplx-arith-tests.lfe ├── unit-cmplx-exp-tests.lfe ├── unit-cmplx-ops-tests.lfe ├── unit-cmplx-polar-tests.lfe ├── unit-cmplx-tests.lfe ├── unit-cmplx-trig-tests.lfe └── unit-cmplx-util-tests.lfe /.gitignore: -------------------------------------------------------------------------------- 1 | _build 2 | *.sublime-project 3 | *.sublime-workspace 4 | *.beam 5 | .eunit 6 | debug-* 7 | ebin/* 8 | bin/expm 9 | *.dump 10 | .rebar 11 | .eunit 12 | rebar/* 13 | .rebar/* 14 | rebar3.crashdump 15 | logs/* 16 | *~ 17 | \#*\# 18 | /.emacs.desktop 19 | /.emacs.desktop.lock 20 | *.elc 21 | auto-save-list 22 | tramp 23 | .\#* 24 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: erlang 2 | install: true 3 | before_script: 4 | - wget https://s3.amazonaws.com/rebar3/rebar3 5 | - chmod +x rebar3 6 | env: PATH=".:$PATH" 7 | script: 8 | - make build-all 9 | - make check 10 | otp_release: 11 | - 19.1 12 | - 18.3 13 | - 17.5 14 | - R16B03-1 15 | - R15B03 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2016 Duncan McGreggor 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = complex 2 | ROOT_DIR = $(shell pwd) 3 | REPO = $(shell git config --get remote.origin.url) 4 | LFE = _build/dev/lib/lfe/bin/lfe 5 | 6 | include priv/make/code.mk 7 | include priv/make/docs.mk 8 | 9 | 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # complex 2 | 3 | [![Build Status][travis badge]][travis] [![LFE Versions][lfe badge]][lfe] [![Erlang Versions][erlang badge]][versions] [![Tags][github tags badge]][github tags] [![Downloads][hex downloads]][hex package] 4 | 5 | *LFE support for numbers both real and imagined* 6 | 7 | [![Complex project logo][logo]][logo-large] 8 | 9 | ## Table of Contents 10 | 11 | * [Introduction](#introduction-) 12 | * [Installation](#installation-) 13 | * [Usage](#usage-) 14 | * [Creating Complex Numbers](#creating-complex-numbers-) 15 | * [From Strings](#creating-from-strings-) 16 | * [From Atoms](#creating-from-atoms-) 17 | * [Convenience Functions](#convenience-functions-) 18 | * [Printing](#printing-complex-numbers-) 19 | * [Common Numbers](#common-numbers-) 20 | * [Math](#math-) 21 | * [Arithmatic](#arithmatic-) 22 | * [Operations](#operations-) 23 | * [Powers](#powers-) 24 | * [API](#api-) 25 | * [License](#license-) 26 | 27 | ## Introduction [↟](#table-of-contents) 28 | 29 | This library provides complex number data types (LFE records for rectangular 30 | and polar complex numbers) as well as many mathematical operations which 31 | support the complex data type. For a full list of functions in the API,see 32 | the bottom of this README file. 33 | 34 | ## Installation [↟](#table-of-contents) 35 | 36 | Just add it to your `rebar.config` deps: 37 | 38 | ```erlang 39 | {deps, [ 40 | {complex, {git, "https://github.com/lfex/complex.git", {branch, "master"}}} 41 | ]}. 42 | ``` 43 | 44 | At this point, the complex library will be avialable in your project's dependencies. 45 | 46 | ## Usage [↟](#table-of-contents) 47 | 48 | ### Creating Complex Numbers [↟](#table-of-contents) 49 | 50 | Create some new complex numbers using the standard rectangular coordinates: 51 | 52 | ```lisp 53 | lfe> (set z1 (complex:new 4 -2)) 54 | #(complex 4 -2) 55 | lfe> (set z2 (complex:new 4 2)) 56 | #(complex 4 2) 57 | ``` 58 | 59 | Create complex numbers using polar coordinates: 60 | 61 | ```lisp 62 | lfe> (set z3 (complex:new-polar 4 (* -0.5 (math:pi)))) 63 | #(complex-polar 4 -1.5707963267948966) 64 | lfe> (set z4 (complex:new-polar 4 (* 0.5 (math:pi)))) 65 | #(complex-polar 4 1.5707963267948966) 66 | ``` 67 | 68 | #### Creating from Strings [↟](#table-of-contents) 69 | 70 | You can also create a new complex number using a string value: 71 | 72 | ```lisp 73 | lfe> (complex:new "4-2i") 74 | #(complex 4 -2) 75 | lfe> (complex:new "4+2i") 76 | #(complex 4 2) 77 | ``` 78 | 79 | There are rules for using complex strings, though: 80 | 81 | * there can be no spaces in the complex string 82 | * you must always include the real part, even if the value is zero: 83 | `(complex:new "0+2i")` 84 | * the imaginary part must always include the number, even if the 85 | component value is `1`: `(complex:new "2+1i")` 86 | 87 | Optional usage: 88 | 89 | * if the imaginary component is zero, you may leave it 90 | off: `(complex:new "2")` 91 | * you may use `i`, `j`, `I`, or `J` to indicate the imaginary 92 | part: `(complex:new "-4+2j")` 93 | * you may use floating point values: `(complex:new "1.2-3.4i")` 94 | * you may use scientific notation: 95 | `(complex:new "1.2e3-4.5e-6i")` 96 | 97 | #### Creating from Atoms [↟](#table-of-contents) 98 | 99 | Using the same rules, you may use atoms to create a new complex number: 100 | 101 | ```lisp 102 | lfe> (complex:new '4-2i) 103 | #(complex 4 -2) 104 | lfe> (complex:new '4.3+2.1i) 105 | #(complex 4.3 2.1) 106 | lfe> (complex:new '4.3e10-2.1e-20j) 107 | #(complex 4.3e10 -2.1e-20) 108 | ``` 109 | 110 | However, do keep in mind that the use of atoms to create complex numbers 111 | should not be done automatically in large numbers, or you run the risk 112 | of exhuasting the Erlang atom table and thus crashing your VM. 113 | 114 | ### Convenience Functions [↟](#table-of-contents) 115 | 116 | For the rest of the usage, we'll just `slurp` so that the calls are easier to type: 117 | 118 | ```lisp 119 | lfe> (slurp "src/complex.lfe") 120 | #(ok complex) 121 | ``` 122 | 123 | #### Printing Complex Numbers [↟](#table-of-contents) 124 | 125 | Print the numbers we previously defined: 126 | 127 | ```lisp 128 | lfe> (format z1) 129 | 4-2i 130 | ok 131 | lfe> (format z2) 132 | 4+2i 133 | ok 134 | lfe> (format z3) 135 | 0-4.0i 136 | ok 137 | lfe> (format z4) 138 | 0+4.0i 139 | ok 140 | ``` 141 | 142 | Note that `format/1` will convert a polar coordinate to rectangular; thus the 143 | last two above. 144 | 145 | #### Common Numbers [↟](#table-of-contents) 146 | 147 | ```lisp 148 | lfe> (one) 149 | #(complex 1 0) 150 | lfe> (two) 151 | #(complex 2 0) 152 | lfe> (i) 153 | #(complex 0 1) 154 | lfe> (pi) 155 | #(complex 3.141592653589793 0) 156 | lfe> (e) 157 | #(complex 2.718281828459045 0) 158 | lfe> (-pi/2) 159 | #(complex -1.5707963267948966 0) 160 | ``` 161 | 162 | ### Math [↟](#table-of-contents) 163 | 164 | #### Arithmatic [↟](#table-of-contents) 165 | 166 | ```lisp 167 | lfe> (add (complex 4 2) (i)) 168 | #(complex 4 3) 169 | lfe> (sub (complex 4 2) (i)) 170 | #(complex 4 1) 171 | lfe> (mult (complex 4 2) (i)) 172 | #(complex -2 4) 173 | lfe> (div (complex 4 2) (i)) 174 | #(complex 2.0 -4.0) 175 | ``` 176 | 177 | Note that `complex/2` is an alias for `new/2`; it just looks nicer 178 | when not using the module name. 179 | 180 | #### Operations [↟](#table-of-contents) 181 | 182 | ```lisp 183 | lfe> (conj z2) 184 | #(complex 4 -2) 185 | lfe> (eq z1 z2) 186 | false 187 | lfe> (eq z1 (conj z2)) 188 | true 189 | lfe> (inv z1) 190 | #(complex 0.2 0.1) 191 | lfe> (inv z2) 192 | #(complex 0.2 -0.1) 193 | lfe> (modulus z1) 194 | 4.47213595499958 195 | lfe> (modulus z1 #(complex)) 196 | #(complex 4.47213595499958 0) 197 | lfe> (modulus (complex-polar 4 (math:pi))) 198 | 4 199 | lfe> (arg (complex-polar 4 (math:pi))) 200 | 3.141592653589793 201 | ``` 202 | 203 | ```lisp 204 | lfe> (sqrt (-one)) 205 | #(complex 0.0 1.0) 206 | ok 207 | lfe> (eq (sqrt (-one)) (i)) 208 | true 209 | ``` 210 | 211 | #### Powers [↟](#table-of-contents) 212 | 213 | Using exponents to demonstrate the cyclic values of the powers of *i*: 214 | 215 | ```lisp 216 | lfe> (format (pow (i) 0)) 217 | 1+0i 218 | ok 219 | lfe> (format (pow (i) 1)) 220 | 0+1i 221 | ok 222 | lfe> (format (pow (i) 2)) 223 | -1+0i 224 | ok 225 | lfe> (format (pow (i) 3)) 226 | 0-1i 227 | ok 228 | lfe> (format (pow (i) 4)) 229 | 1+0i 230 | ok 231 | ``` 232 | 233 | Negative powers are supported: 234 | 235 | ```lisp 236 | lfe> (pow (pi) -2) 237 | #(complex 0.10132118364233778 0.0) 238 | lfe> (pow (two) -4) 239 | #(complex 0.0625 0.0) 240 | ``` 241 | 242 | As are fractional powers (roots): 243 | 244 | ```lisp 245 | lfe> (pow 16 (/ 1 2)) 246 | #(complex 4.0 0) 247 | lfe> (pow 16 (/ 1 4)) 248 | #(complex 2.0 0) 249 | lfe> (pow 16 (/ 1 8)) 250 | #(complex 1.4142135623730951 0) 251 | ``` 252 | 253 | See the [unit tests](tests) for a greater number of examples. 254 | 255 | ## API [↟](#table-of-contents) 256 | 257 | The list of functions currently supported by the complex library are as follows: 258 | 259 | ```lisp 260 | complex:-2pi/0 261 | complex:->atom/1 262 | complex:->str/1 263 | complex:-i/0 264 | complex:-i/2/0 265 | complex:-one/0 266 | complex:-pi/0 267 | complex:-pi/2/0 268 | complex:-two/0 269 | complex:2pi/0 270 | complex:abs/1 271 | complex:abs/2 272 | complex:acos/1 273 | complex:acosh/1 274 | complex:acot/1 275 | complex:acoth/1 276 | complex:acsc/1 277 | complex:acsch/1 278 | complex:add/2 279 | complex:angle/1 280 | complex:arg/1 281 | complex:arg/2 282 | complex:asec/1 283 | complex:asech/1 284 | complex:asin/1 285 | complex:asinh/1 286 | complex:atan/1 287 | complex:atanh/1 288 | complex:atom->/1 289 | complex:complex/2 290 | complex:complex-polar/2 291 | complex:complex-polar?/1 292 | complex:complex?/1 293 | complex:conj/1 294 | complex:cos/1 295 | complex:cosh/1 296 | complex:cot/1 297 | complex:coth/1 298 | complex:csc/1 299 | complex:csch/1 300 | complex:distance/1 301 | complex:div/2 302 | complex:e/0 303 | complex:eeq/2 304 | complex:eq/2 305 | complex:eq/3 306 | complex:exp/1 307 | complex:i/0 308 | complex:i/2/0 309 | complex:img/1 310 | complex:inv/1 311 | complex:ln/1 312 | complex:modsq/1 313 | complex:modulus/1 314 | complex:modulus/2 315 | complex:mult/2 316 | complex:neg/1 317 | complex:new/0 318 | complex:new/1 319 | complex:new/2 320 | complex:new-polar/0 321 | complex:new-polar/1 322 | complex:new-polar/2 323 | complex:one/0 324 | complex:phase/1 325 | complex:phi/1 326 | complex:pi/0 327 | complex:pi/2/0 328 | complex:polar->rect/1 329 | complex:polar->rect/2 330 | complex:pow/2 331 | complex:print/1 332 | complex:r/1 333 | complex:real/1 334 | complex:rect->polar/1 335 | complex:sec/1 336 | complex:sech/1 337 | complex:sign/1 338 | complex:sin/1 339 | complex:sinh/1 340 | complex:sqrt/1 341 | complex:str->/1 342 | complex:sub/2 343 | complex:tan/1 344 | complex:tanh/1 345 | complex:two/0 346 | ``` 347 | 348 | ## License [↟](#table-of-contents) 349 | 350 | Apache Version 2 License 351 | 352 | Copyright © 2015-2020, Duncan McGreggor 353 | 354 | 355 | 356 | [logo]: priv/images/complex-function-crop-x250.png 357 | [logo-large]: priv/images/complex-function-crop-x1000.png 358 | [org]: https://github.com/lfex 359 | [github]: https://github.com/lfex/complex 360 | [gitlab]: https://gitlab.com/lfex/complex 361 | [travis]: https://travis-ci.org/lfex/complex 362 | [travis badge]: https://img.shields.io/travis/lfex/complex.svg 363 | [lfe]: https://github.com/rvirding/lfe 364 | [lfe badge]: https://img.shields.io/badge/lfe-1.3.0-blue.svg 365 | [erlang badge]: https://img.shields.io/badge/erlang-19%20to%2023-blue.svg 366 | [versions]: https://github.com/lfex/complex/blob/master/.travis.yml 367 | [github tags]: https://github.com/lfex/complex/tags 368 | [github tags badge]: https://img.shields.io/github/tag/lfex/complex.svg 369 | [github downloads]: https://img.shields.io/github/downloads/lfex/complex/total.svg 370 | [hex badge]: https://img.shields.io/hexpm/v/complex_math.svg?maxAge=2592000 371 | [hex package]: https://hex.pm/packages/complex_math 372 | [hex downloads]: https://img.shields.io/hexpm/dt/complex_math.svg 373 | -------------------------------------------------------------------------------- /include/data-types.lfe: -------------------------------------------------------------------------------- 1 | (defrecord complex 2 | real 3 | img) 4 | 5 | (defrecord complex-polar 6 | mod 7 | arg) 8 | 9 | (defun loaded-complex-data-types () 10 | "This is just a dummy function for display purposes when including from the 11 | REPL (the last function loaded has its name printed in stdout). 12 | This function needs to be the last one in this include." 13 | 'ok) -------------------------------------------------------------------------------- /include/options.lfe: -------------------------------------------------------------------------------- 1 | (defrecord opts 2 | tol) 3 | 4 | (defun opts->rec 5 | ((`(#(tol ,tol))) 6 | (make-opts tol tol)) 7 | ((_) 8 | (make-opts))) 9 | 10 | (defun loaded-complex-options () 11 | "This is just a dummy function for display purposes when including from the 12 | REPL (the last function loaded has its name printed in stdout). 13 | This function needs to be the last one in this include." 14 | 'ok) -------------------------------------------------------------------------------- /priv/images/complex-function-crop-x1000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfex/complex/f030e880d729f4478835fafbb54f2a2816c9f628/priv/images/complex-function-crop-x1000.png -------------------------------------------------------------------------------- /priv/images/complex-function-crop-x250.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfex/complex/f030e880d729f4478835fafbb54f2a2816c9f628/priv/images/complex-function-crop-x250.png -------------------------------------------------------------------------------- /priv/images/complex-function-crop-x500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfex/complex/f030e880d729f4478835fafbb54f2a2816c9f628/priv/images/complex-function-crop-x500.png -------------------------------------------------------------------------------- /priv/images/complex-function-crop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfex/complex/f030e880d729f4478835fafbb54f2a2816c9f628/priv/images/complex-function-crop.png -------------------------------------------------------------------------------- /priv/make/code.mk: -------------------------------------------------------------------------------- 1 | compile: 2 | rebar3 compile 3 | 4 | check: 5 | rebar3 as test lfe test -t unit 6 | 7 | repl: 8 | @rebar3 as dev compile 9 | @$(LFE) -pa `rebar3 as dev path -s " -pa "` 10 | 11 | shell: 12 | @rebar3 shell 13 | 14 | clean: 15 | @rebar3 clean 16 | @rm -rf ebin/* _build/*/lib/$(PROJECT) rebar.lock 17 | 18 | clean-all: clean 19 | @rebar3 as dev lfe clean 20 | 21 | push: 22 | git push github master 23 | git push gitlab master 24 | 25 | push-tags: 26 | git push github --tags 27 | git push gitlab --tags 28 | 29 | push-all: push push-tags 30 | 31 | build-github: clean 32 | rebar3 compile 33 | 34 | build-gitlab: clean 35 | rebar3 as gitlab compile 36 | 37 | build-hexpm: clean 38 | rebar3 as hexpm compile 39 | 40 | build-all: build-github build-gitlab build-hexpm 41 | 42 | publish: clean 43 | rebar3 as hexpm hex publish 44 | -------------------------------------------------------------------------------- /priv/make/docs.mk: -------------------------------------------------------------------------------- 1 | DOCS_DIR = $(ROOT_DIR)/docs 2 | GUIDE_DIR = $(DOCS_DIR)/user-guide 3 | GUIDE_BUILD_DIR = $(GUIDE_DIR)/build 4 | DOCS_PROD_DIR = $(DOCS_DIR)/master 5 | API_PROD_DIR = $(DOCS_PROD_DIR)/current/api 6 | GUIDE_PROD_DIR = $(DOCS_PROD_DIR)/current/user-guide 7 | SLATE_GIT_HACK = $(DOCS_DIR)/.git 8 | LOCAL_DOCS_HOST = localhost 9 | LOCAL_DOCS_PORT = 5099 10 | 11 | $(SLATE_GIT_HACK): 12 | @ln -s $(ROOT_DIR)/.git $(DOCS_DIR) 13 | 14 | docs-setup: 15 | @echo "\nInstalling and setting up dependencies ..." 16 | @cd $(DOCS_DIR) && bundle install 17 | 18 | docs-clean: 19 | @echo "\nCleaning build directories ..." 20 | @rm -rf $(GUIDE_BUILD_DIR) $(API_PROD_DIR) $(GUIDE_PROD_DIR) 21 | 22 | docs-lodox: 23 | @echo 24 | @rebar3 lfe lodox 25 | 26 | docs-slate: 27 | @echo 28 | @cd $(GUIDE_DIR) && bundle exec middleman build --clean 29 | @mkdir $(GUIDE_PROD_DIR) 30 | @cp -r $(GUIDE_BUILD_DIR)/* $(GUIDE_PROD_DIR)/ 31 | 32 | docs: clean compile docs-clean $(SLATE_GIT_HACK) 33 | @echo "\nBuilding docs ...\n" 34 | @make docs-lodox 35 | @make docs-slate 36 | 37 | devdocs: docs 38 | @echo 39 | @echo "Running docs server on http://$(LOCAL_DOCS_HOST):$(LOCAL_DOCS_PORT) ... (To quit, hit ^c twice)" 40 | @echo 41 | @erl -s inets -noshell -eval 'inets:start(httpd,[{server_name,"devdocs"},{document_root, "$(DOCS_PROD_DIR)"},{server_root, "$(DOCS_PROD_DIR)"},{port, $(LOCAL_DOCS_PORT)},{mime_types,[{"html","text/html"},{"htm","text/html"},{"js","text/javascript"},{"css","text/css"},{"gif","image/gif"},{"jpg","image/jpeg"},{"jpeg","image/jpeg"},{"png","image/png"}]}]).' 42 | 43 | setup-temp-repo: $(SLATE_GIT_HACK) 44 | @echo "\nSetting up temporary git repos for gh-pages ...\n" 45 | @rm -rf $(DOCS_PROD_DIR)/.git $(DOCS_PROD_DIR)/*/.git 46 | @cd $(DOCS_PROD_DIR) && git init 47 | @cd $(DOCS_PROD_DIR) && git add * > /dev/null 48 | @cd $(DOCS_PROD_DIR) && git commit -a -m "Generated content." > /dev/null 49 | 50 | teardown-temp-repo: 51 | @echo "\nTearing down temporary gh-pages repos ..." 52 | @rm $(DOCS_DIR)/.git $(GUIDE_DIR)/Gemfile.lock 53 | @rm -rf $(DOCS_PROD_DIR)/.git $(DOCS_PROD_DIR)/*/.git 54 | 55 | publish-docs: docs setup-temp-repo 56 | @echo "\nPublishing docs ...\n" 57 | @cd $(DOCS_PROD_DIR) && git push -f $(REPO) master:gh-pages 58 | @make teardown-temp-repo 59 | 60 | .PHONY: docs 61 | -------------------------------------------------------------------------------- /rebar.config: -------------------------------------------------------------------------------- 1 | {erl_opts, [debug_info, {no_auto_import, [{abs,1}]}]}. 2 | 3 | {deps, [ 4 | {lfe, {git, "https://github.com/lfe/lfe.git", {tag, "2.0"}}} 5 | ]}. 6 | 7 | {plugins, [ 8 | {rebar3_lfe, {git, "https://github.com/lfe-rebar3/rebar3_lfe.git", {branch, "release/0.3.x"}}} 9 | ]}. 10 | 11 | {provider_hooks, [ 12 | {pre, [{compile, {lfe, compile}}]} 13 | ]}. 14 | 15 | {profiles, [ 16 | {test, [ 17 | {deps, [ 18 | {ltest, {git, "https://github.com/lfex/ltest.git", {branch, "release/0.11.x"}}}]}, 19 | {eunit_opts, [verbose]}, 20 | {src_dirs, ["src", "test"]} 21 | ]} 22 | ]}. 23 | -------------------------------------------------------------------------------- /src/cmplx-util.lfe: -------------------------------------------------------------------------------- 1 | (defmodule cmplx-util 2 | (export 3 | (get-version 0) 4 | (get-versions 0) 5 | (->str 1) 6 | (str-> 1) 7 | (->atom 1) 8 | (atom-> 1) 9 | (get-match 1) 10 | (print-api-functions 0) 11 | (zero-check 2))) 12 | 13 | (include-lib "include/data-types.lfe") 14 | 15 | (defun get-version () 16 | (rebar3_lfe_version:app_version 'complex)) 17 | 18 | (defun get-versions () 19 | (rebar3_lfe_version:versions '(complex))) 20 | 21 | ;; Convert to string (list): 22 | ;; 23 | ;; lfe> (complex:->str c1) 24 | ;; ("1" 32 "+" "2" 105) 25 | ;; lfe> (complex:->str c2) 26 | ;; ("3" 32 () "-5" 105) 27 | 28 | (defun ->str 29 | (((match-complex real r img i)) (when (>= i 0)) 30 | (->str r i "+")) 31 | (((match-complex real r img i)) 32 | (->str r i ""))) 33 | 34 | (defun ->str (r i pos) 35 | (io_lib:format "~p~s~pi" `(,(zero-check r 1.0e-15) 36 | ,pos 37 | ,(zero-check i 1.0e-15)))) 38 | 39 | (defun ->atom 40 | (((match-complex real r img i)) (when (>= i 0)) 41 | (list_to_atom (->str r i "+"))) 42 | (((match-complex real r img i)) 43 | (list_to_atom (->str r i "")))) 44 | 45 | (defun str-> 46 | ((z-str) 47 | (let ((match (get-match z-str))) 48 | ;;(io:format "Match: ~p~n" (list match)) ; debug 49 | (case match 50 | (`#(match (,_ ,real)) 51 | (complex:new (str->num real))) 52 | (`#(match (,_ ,real ,_ ,_)) 53 | (complex:new (str->num real))) 54 | (`#(match (,_ ,real ,_ ,_ ,_)) 55 | (complex:new (str->num real))) 56 | (`#(match (,_ "" ,_ ,_ ,_ ,_ ,img)) 57 | (complex:new 0 (str->num img))) 58 | (`#(match (,_ "" ,_ ,_ ,_ ,_ ,img ,_ ,_)) 59 | (complex:new 0 (str->num img))) 60 | (`#(match (,_ "" ,_ ,_ ,_ ,_ ,img ,_ ,_ ,_)) 61 | (complex:new 0 (str->num img))) 62 | (`#(match (,_ ,real ,_ ,_ ,_ ,_ ,img)) 63 | (complex:new (str->num real) 64 | (str->num img))) 65 | (`#(match (,_ ,real ,_ ,_ ,_ ,_ ,img ,_ ,_)) 66 | (complex:new (str->num real) 67 | (str->num img))) 68 | (`#(match (,_ ,real ,_ ,_ ,_ ,_ ,img ,_ ,_ ,_)) 69 | (complex:new (str->num real) 70 | (str->num img))) 71 | (`#(error ,msg) 72 | `#(error ,msg)) 73 | (_ #(error conversion-failure)))))) 74 | 75 | (defun str->num (num-str) 76 | (try (list_to_integer num-str) 77 | (catch ((tuple _ _ _) 78 | (try (list_to_float num-str) 79 | (catch ((tuple _ _ _) 80 | (error `#(conversion-error ,num-str))))))))) 81 | 82 | (defun atom-> (atom) 83 | (str-> (atom_to_list atom))) 84 | 85 | (defun get-img-pattern () 86 | (let* ((begin "^(") 87 | (end ")$") 88 | (sign "([-+])?") 89 | (int "\\d+") 90 | (frac "(\\.\\d+)") 91 | (sci "([eE][+-]?\\d+)?") 92 | (img (++ "((" sign int "(" frac sci ")?)[iIjJ])?"))) 93 | (get-pattern 94 | (re:compile (++ begin img end))))) 95 | 96 | (defun get-full-pattern () 97 | (let* ((begin "^(") 98 | (end ")$") 99 | (sign "[-+]") 100 | (int "\\d+") 101 | (frac "(\\.\\d+)") 102 | (sci "([eE][+-]?\\d+)?") 103 | (real (++ "(" sign "?" int "(" frac sci ")?)?")) 104 | (img (++ "((" sign int "(" frac sci ")?)[iIjJ])?"))) 105 | (get-pattern 106 | (re:compile (++ begin real img end))))) 107 | 108 | (defun get-pattern 109 | ((`#(ok ,pattern)) 110 | pattern) 111 | ((x) 112 | `#(error ,x))) 113 | 114 | (defun get-match (z-str) 115 | (let ((full (re:run z-str (get-full-pattern) '(#(capture all_but_first list))))) 116 | (case full 117 | (`#(match ,_) full) 118 | (_ (let ((img (re:run z-str (get-img-pattern) '(#(capture all_but_first list))))) 119 | ;;(io:format "Got img match: ~p~n" (list img)) ; debug 120 | (case img 121 | (`#(match (,_ ,_ ,img)) `#(match ("" "" "" "" "" "" ,img))) 122 | (_ '#(error complex-number-parse-failure)))))))) 123 | 124 | (defun check-function 125 | ((`#(,func-name ,arity)) 126 | (let ((skip '(module_info 127 | get-version 128 | get-versions 129 | loaded-complex-data-types 130 | loaded-complex-options 131 | loaded-complex-api 132 | loaded-complex 133 | zero-check 134 | get-match 135 | print-api-functions))) 136 | (if (lists:member func-name skip) 137 | 'false 138 | `#(true #(,func-name ,arity)))))) 139 | 140 | (defun get-api-functions () 141 | (lists:filtermap 142 | #'check-function/1 143 | (proplists:get_value 'exports (complex:module_info)))) 144 | 145 | (defun print-function 146 | ((`#(,func-name ,arity)) 147 | (lfe_io:format "complex:~p/~p~n" `(,func-name ,arity)))) 148 | 149 | (defun print-api-functions () 150 | (lists:foreach 151 | #'print-function/1 152 | (lists:sort (get-api-functions)))) 153 | 154 | (defun zero-check (num tol) 155 | (if (< (erlang:abs num) tol) 156 | 0 157 | num)) 158 | -------------------------------------------------------------------------------- /src/complex.app.src: -------------------------------------------------------------------------------- 1 | %% -*- erlang -*- 2 | {application, complex, 3 | [ 4 | %% A quick description of the application. 5 | {description, "LFE support for numbers both real and imagined"}, 6 | 7 | %% The version of the application 8 | {vsn, "0.2.0-rc1"}, 9 | 10 | %% All modules used by the application. 11 | {modules, 12 | [ 13 | complex, 14 | 'complex-util' 15 | ]}, 16 | 17 | %% All of the registered names the application uses. This can be ignored. 18 | {registered, []}, 19 | 20 | %% Applications that are to be started prior to this one. This can be ignored 21 | %% leave it alone unless you understand it well and let the .rel files in 22 | %% your release handle this. 23 | {applications, 24 | [ 25 | kernel, 26 | stdlib 27 | ]}, 28 | 29 | %% OTP application loader will load, but not start, included apps. Again 30 | %% this can be ignored as well. To load but not start an application it 31 | %% is easier to include it in the .rel file followed by the atom 'none' 32 | {included_applications, []}, 33 | 34 | %% configuration parameters similar to those in the config file specified 35 | %% on the command line. can be fetched with gas:get_env 36 | {env, []}, 37 | 38 | %% Package metadata: 39 | {pkg_name, complex_math}, 40 | {maintainers, ["Duncan McGreggor"]}, 41 | {licenses, ["Apache-2"]}, 42 | {links, 43 | [{"GitHub", "https://github.com/lfex/complex"}, 44 | {"Gitlab", "https://gitlab.com/lfex/complex"}, 45 | {"Hex", "https://hex.pm/packages/complex_math"} 46 | ]} 47 | ] 48 | }. 49 | -------------------------------------------------------------------------------- /src/complex.lfe: -------------------------------------------------------------------------------- 1 | (defmodule complex 2 | (export 3 | (new 0) (new 1) (new 2) (complex 2) 4 | (new-polar 0) (new-polar 1) (new-polar 2) (complex-polar 2) 5 | (complex? 1) 6 | (complex-polar? 1) 7 | (real 1) 8 | (img 1) 9 | (r 1) (distance 1) 10 | (phi 1) (angle 1)) 11 | (export 12 | (one 0) 13 | (-one 0) 14 | (two 0) 15 | (-two 0) 16 | (i 0) 17 | (-i 0) 18 | (i/2 0) 19 | (-i/2 0) 20 | (e 0) 21 | (pi 0) 22 | (-pi 0) 23 | (pi/2 0) 24 | (-pi/2 0) 25 | (2pi 0) 26 | (-2pi 0)) 27 | (export 28 | (add 2) 29 | (sub 2) 30 | (mult 2) 31 | (div 2)) 32 | (export 33 | (sign 1) 34 | (neg 1) 35 | (eq 2) (eq 3) 36 | (eeq 2) 37 | (conj 1) 38 | (modsq 1) 39 | (modulus 1) (modulus 2) 40 | (abs 1) (abs 2) 41 | (inv 1) 42 | (arg 1) (arg 2) 43 | (phase 1) 44 | (sqrt 1)) 45 | (export 46 | (pow 2) 47 | (exp 1) 48 | (ln 1)) 49 | (export 50 | (cos 1) (cosh 1) (acos 1) (acosh 1) 51 | (sin 1) (sinh 1) (asin 1) (asinh 1) 52 | (tan 1) (tanh 1) (atan 1) (atanh 1) 53 | (csc 1) (csch 1) (acsc 1) (acsch 1) 54 | (sec 1) (sech 1) (asec 1) (asech 1) 55 | (cot 1) (coth 1) (acot 1) (acoth 1)) 56 | (export 57 | (rect->polar 1) 58 | (polar->rect 1) 59 | (polar->rect 2)) 60 | (compile 61 | #(no_auto_import '(abs 1)))) 62 | 63 | (include-lib "include/data-types.lfe") 64 | (include-lib "include/options.lfe") 65 | 66 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 67 | ;;; Constructors ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 68 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 69 | 70 | (defun new () 71 | (new 0 0)) 72 | 73 | (defun new 74 | ((z-str) (when (is_list z-str)) 75 | (cmplx-util:str-> z-str)) 76 | ((z-atom) (when (is_atom z-atom)) 77 | (cmplx-util:atom-> z-atom)) 78 | ((r) 79 | (new r 0))) 80 | 81 | (defun new (r i) 82 | (make-complex real r img i)) 83 | 84 | (defun complex (r i) 85 | "This function is an alias for new/2 and is provided for aesthetic reasons: 86 | it looks nicer in the REPL calling (complex 1 2) than (new 1 2)." 87 | (new r i)) 88 | 89 | (defun new-polar () 90 | (new-polar 1 0)) 91 | 92 | (defun new-polar (phi) 93 | (new-polar 1 phi)) 94 | 95 | (defun new-polar (r phi) 96 | (make-complex-polar mod r arg phi)) 97 | 98 | (defun complex-polar (r phi) 99 | (new-polar r phi)) 100 | 101 | (defun real (z) 102 | (complex-real z)) 103 | 104 | (defun img (z) 105 | (complex-img z)) 106 | 107 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 108 | ;;; Constants ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 109 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 110 | 111 | (defun one () 112 | (complex 1 0)) 113 | 114 | (defun -one () 115 | (complex -1 0)) 116 | 117 | (defun two () 118 | (complex 2 0)) 119 | 120 | (defun -two () 121 | (complex -2 0)) 122 | 123 | (defun i () 124 | (complex 0 1)) 125 | 126 | (defun -i () 127 | (complex 0 -1)) 128 | 129 | (defun i/2 () 130 | (complex 0 0.5)) 131 | 132 | (defun -i/2 () 133 | (complex 0 -0.5)) 134 | 135 | (defun e () 136 | (complex (math:exp 1) 0)) 137 | 138 | (defun pi () 139 | (complex (math:pi) 0)) 140 | 141 | (defun -pi () 142 | (complex (* -1 (math:pi)) 0)) 143 | 144 | (defun pi/2 () 145 | (complex (* (math:pi) 0.5) 0)) 146 | 147 | (defun -pi/2 () 148 | (complex (* (math:pi) -0.5) 0)) 149 | 150 | (defun 2pi () 151 | (complex (* (math:pi) 2) 0)) 152 | 153 | (defun -2pi () 154 | (complex (* (math:pi) -2) 0)) 155 | 156 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 157 | ;;; Arithmatic ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 158 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 159 | 160 | ;; Setup: 161 | ;; 162 | ;; lfe> (set z1 (complex:new 1 2)) 163 | ;; #(complex 1 2) 164 | ;; lfe> (set z2 (complex:new 3 -5)) 165 | ;; #(complex 3 -5) 166 | 167 | ;; Adding: 168 | ;; 169 | ;; lfe> (complex:add z1 z2) 170 | ;; #(complex 4 -3) 171 | ;; 172 | (defun add 173 | (((match-complex real r1 img i1) 174 | (match-complex real r2 img i2)) 175 | (new (+ r1 r2) (+ i1 i2)))) 176 | 177 | ;; Subtracting: 178 | ;; 179 | ;; lfe> (complex:sub z1 z2) 180 | ;; #(complex -2 7) 181 | ;; lfe> (complex:sub z2 z1) 182 | ;; #(complex 2 -7) 183 | ;; lfe> (complex:sub z1 z1) 184 | ;; #(complex 0 0) 185 | ;; 186 | (defun sub 187 | (((match-complex real r1 img i1) 188 | (match-complex real r2 img i2)) 189 | (new (- r1 r2) (- i1 i2)))) 190 | 191 | ;; Multiplying 192 | ;; 193 | ;; lfe> (complex:* z1 z2) 194 | ;; #(complex 13 -11) 195 | ;; 196 | (defun mult 197 | (((match-complex real r1 img i1) 198 | (match-complex real r2 img i2)) 199 | (new (- (* r1 r2) (* i1 i2)) 200 | (+ (* r1 i2) (* r2 i1))))) 201 | 202 | ;; Division: 203 | ;; 204 | ;; lfe> (complex:div z1 z2) 205 | ;; #(complex -0.20588235294117646 0.3235294117647059) 206 | ;; lfe> (complex:div z2 z1) 207 | ;; #(complex -1.4 -2.2) 208 | ;; 209 | (defun div (z1 z2) 210 | (let* ((denom (complex:real (complex:modsq z2))) 211 | (z3 (mult z1 (complex:conj z2)))) 212 | (complex:new (/ (complex:real z3) denom) 213 | (/ (complex:img z3) denom)))) 214 | 215 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 216 | ;;; Operations ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 217 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 218 | 219 | (defun sign 220 | ((x) (when (< x 0)) 221 | -1) 222 | ((_) 223 | 1)) 224 | 225 | ;; Negation: 226 | ;; 227 | ;; lfe> (complex:neg z1) 228 | ;; #(complex -1 -2) 229 | ;; lfe> (complex:neg z2) 230 | ;; #(complex -3 5) 231 | 232 | (defun neg 233 | (((match-complex real r img i)) 234 | (complex (* -1 r) (* -1 i)))) 235 | 236 | ;; Equality: 237 | ;; 238 | ;; lfe> (complex:eq z1 z2) 239 | ;; false 240 | ;; lfe> (complex:eq z1 (complex:new 1 2)) 241 | ;; true 242 | 243 | (defun eq 244 | "Equal." 245 | (((match-complex real r1 img i1) 246 | (match-complex real r2 img i2)) 247 | (if (and (== r1 r2) 248 | (== i1 i2)) 249 | 'true 250 | 'false)) 251 | (((match-complex-polar mod r1 arg phi1) 252 | (match-complex-polar mod r2 arg phi2)) 253 | (if (and (== r1 r2) 254 | (== phi1 phi2)) 255 | 'true 256 | 'false))) 257 | 258 | (defun eq 259 | "Equal, within a tolerance. 260 | 261 | Sometimes it's useful to set a tolerance level for what floating points 262 | numbers should be considered 0. This is done in the unit tests for this 263 | library, assuming any float less that 1.0e-15 to be a zero, e.g. The 264 | following version of the equality function take an options list or 265 | options record, and if the field 'tol' is present and set to something 266 | other than 'undefined', a tolerance check will be performed." 267 | ((z1 z2 '()) 268 | (eq z1 z2)) 269 | ((z1 z2 opts) (when (is_list opts)) 270 | (eq z1 z2 (opts->rec opts))) 271 | ((z1 z2 (match-opts tol 'undefined)) 272 | (eq z1 z2)) 273 | (((match-complex real r1 img i1) 274 | (match-complex real r2 img i2) 275 | (match-opts tol tol)) 276 | (if (and (== (complex:zero-check r1 tol) 277 | (complex:zero-check r2 tol)) 278 | (== (complex:zero-check i1 tol) 279 | (complex:zero-check i2 tol))) 280 | 'true 281 | 'false)) 282 | ((z1 z2 _) 283 | (eq z1 z2))) 284 | 285 | (defun eeq 286 | "Exactly equal." 287 | (((match-complex real r1 img i1) 288 | (match-complex real r2 img i2)) 289 | (if (and (=:= r1 r2) 290 | (=:= i1 i2)) 291 | 'true 292 | 'false))) 293 | 294 | ;; Conjugate: 295 | ;; 296 | ;; lfe> (complex:conj z1) 297 | ;; #(complex 1 -2) 298 | ;; lfe> (complex:conj z2) 299 | ;; #(complex 3 5) 300 | 301 | (defun conj 302 | (((match-complex real r img i)) 303 | (complex r (* -1 i)))) 304 | 305 | (defun modsq (z) 306 | (mult z (conj z))) 307 | 308 | (defun modulus 309 | (((match-complex-polar mod r)) 310 | r) 311 | ((z) 312 | (math:sqrt (real (modsq z))))) 313 | 314 | (defun modulus 315 | ((z #(complex)) 316 | (complex (modulus z) 0))) 317 | 318 | (defun abs (z) 319 | (modulus z)) 320 | 321 | (defun abs (z opt) 322 | (modulus z opt)) 323 | 324 | ;; Inverse: 325 | ;; 326 | ;; lfe> (complex:inv z1) 327 | ;; #(complex 0.2 -0.4) 328 | ;; lfe> (complex:inv z2) 329 | ;; #(complex 0.08823529411764706 0.14705882352941177) 330 | 331 | (defun inv (z) 332 | (div (conj z) (modsq z))) 333 | 334 | (defun arg 335 | (((match-complex real r img i)) 336 | (arg r i)) 337 | (((match-complex-polar arg phi)) 338 | phi)) 339 | 340 | (defun arg 341 | ;; ((r i) (when (> r 0)) 342 | ;; (math:atan2 i r)) 343 | ;; ((r i) (when (and (< r 0) (< i 0))) 344 | ;; (- (math:atan2 i r) (math:pi))) 345 | ;; ((r i) (when (and (< r 0) (>= i 0))) 346 | ;; (+ (math:atan2 i r) (math:pi))) 347 | ((r i) (when (andalso (== r 0) (== i 0))) 348 | 'undefined) 349 | ((r i) 350 | (math:atan2 i r)) 351 | ;; ((r i) (when (and (== r 0) (> i 0))) 352 | ;; (/ (math:pi) 2)) 353 | ;; ((r i) (when (and (== r 0) (< i 0))) 354 | ;; (/ (math:pi -2))) 355 | ) 356 | 357 | (defun phase (z) 358 | (arg z)) 359 | 360 | ;; Square Root: 361 | ;; 362 | ;; lfe> (complex:sqrt (complex:new -1 0)) 363 | ;; #(complex 0.0 1.0) 364 | ;; lfe> (complex:sqrt z1) 365 | ;; #(complex 1.7320508075688772 1.4142135623730951) 366 | ;; lfe> (complex:sqrt z2) 367 | ;; #(complex 4.301162633521313 -3.9370039370059056) 368 | 369 | (defun sqrt 370 | (((= (match-complex real r img i) z)) 371 | (let* ((abs-z (abs z)) 372 | (neg-r (* -1 r)) 373 | (r2 (math:sqrt (/ (+ r abs-z) 2))) 374 | (i2 (* (sign i) (math:sqrt (/ (+ neg-r abs-z) 2))))) 375 | (complex r2 i2)))) 376 | 377 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 378 | ;;; Exponential Functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 379 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 380 | 381 | (defun pow 382 | ((_ 0) 383 | (complex:one)) 384 | ((z n) (when (is_integer z)) 385 | (complex:new (math:pow z n) 0)) 386 | ((z n) (when (>= n 1)) 387 | (positive-integer-powers z n)) 388 | ((z n) (when (and (> n -1) (< n 1))) 389 | (root z n)) 390 | ((z n) (when (=< n -1)) 391 | (negative-integer-powers z n))) 392 | 393 | (defun positive-integer-powers (z n) 394 | (lists:foldl (lambda (x acc) 395 | (mult x acc)) 396 | (one) 397 | (lists:duplicate n z))) 398 | 399 | (defun negative-integer-powers (z n) 400 | (complex:div (one) 401 | (positive-integer-powers z (abs n)))) 402 | 403 | (defun root (z n) 404 | (cond 405 | ((complex? z) 406 | (root-rect z n)) 407 | ((complex-polar? z) 408 | (root-polar z n)) 409 | ('true 410 | (complex:new (math:pow z n) 0)))) 411 | 412 | (defun root-rect 413 | ((z 0.5) 414 | (complex:sqrt z)) 415 | ((z n) 416 | (root-polar (rect->polar z) n))) 417 | 418 | (defun root-polar 419 | (((match-complex-polar mod r arg phi) n) 420 | (mult (complex (math:pow r n) 0) 421 | (complex (math:cos (* phi n)) 422 | (math:sin (* phi n)))))) 423 | 424 | (defun exp 425 | (((match-complex real r img i)) 426 | (complex (* (math:exp r) (math:cos i)) 427 | (* (math:exp r) (math:sin i))))) 428 | 429 | (defun ln 430 | (((= (match-complex real r img i) z)) 431 | (complex (math:log (modulus z)) 432 | (arg z)))) 433 | 434 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 435 | ;;; Trigonometric Functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 436 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 437 | 438 | (defun sin 439 | (((match-complex real r img i)) 440 | (complex (* (math:sin r) (math:cosh i)) 441 | (* (math:cos r) (math:sinh i))))) 442 | 443 | (defun cos 444 | (((match-complex real r img i)) 445 | (complex (* (math:cos r) (math:cosh i)) 446 | (* -1 (math:sin r) (math:sinh i))))) 447 | 448 | (defun tan (z) 449 | (div (sin z) 450 | (cos z))) 451 | 452 | (defun csc (z) 453 | (div (one) 454 | (sin z))) 455 | 456 | (defun sec (z) 457 | (div (one) 458 | (cos z))) 459 | 460 | (defun cot (z) 461 | (div (one) 462 | (tan z))) 463 | 464 | ;; Hyperbolic trigonometric functions 465 | 466 | (defun sinh 467 | (((match-complex real r img i)) 468 | (complex (* (math:sinh r) (math:cos i)) 469 | (* (math:cosh r) (math:sin i))))) 470 | 471 | (defun cosh 472 | (((match-complex real r img i)) 473 | (complex (* (math:cosh r) (math:cos i)) 474 | (* -1 (math:sinh r) (math:sin i))))) 475 | 476 | (defun tanh (z) 477 | (div (sinh z) 478 | (cosh z))) 479 | 480 | (defun csch (z) 481 | (div (one) 482 | (sinh z))) 483 | 484 | (defun sech (z) 485 | (div (one) 486 | (cosh z))) 487 | 488 | (defun coth (z) 489 | (div (one) 490 | (tanh z))) 491 | 492 | ;; Inverse trigonometric functions 493 | 494 | (defun asin (z) 495 | (mult 496 | (-i) 497 | (ln (add (mult z (i)) 498 | (sqrt 499 | (sub (one) (pow z 2))))))) 500 | 501 | (defun acos (z) 502 | (mult 503 | (-i) 504 | (ln (add z (mult (i) 505 | (sqrt 506 | (sub (one) 507 | (pow z 2)))))))) 508 | 509 | (defun atan (z) 510 | (mult 511 | (i/2) 512 | (ln (div (add (i) z) 513 | (sub (i) z))))) 514 | 515 | (defun acsc (z) 516 | (mult 517 | (-i) 518 | (ln (add (div (i) z) 519 | (sqrt (sub (one) 520 | (div (one) 521 | (pow z 2)))))))) 522 | 523 | (defun asec (z) 524 | (mult 525 | (i) 526 | (ln (div (add (one) 527 | (sqrt 528 | (sub (one) (pow z 2)))) 529 | z)))) 530 | 531 | (defun acot (z) 532 | (sub 533 | (mult 534 | (i/2) 535 | (ln (sub (one) (div (i) z)))) 536 | (mult 537 | (i/2) 538 | (ln (add (one) (div (i) z)))))) 539 | 540 | ;; Inverse hyperbolic trigonometric functions 541 | 542 | (defun asinh (z) 543 | (ln (add z 544 | (sqrt 545 | (add (one) (pow z 2)))))) 546 | 547 | (defun acosh (z) 548 | (ln (add z (mult 549 | (sqrt (sub z (one))) 550 | (sqrt (add z (one))))))) 551 | 552 | (defun atanh (z) 553 | (add 554 | (div (ln (sub (one) z)) 555 | (-two)) 556 | (div (ln (add (one) z)) 557 | (two)))) 558 | 559 | (defun acsch (z) 560 | (ln (add 561 | (sqrt (add (one) 562 | (div (one) 563 | (pow z 2)))) 564 | (div (one) z)))) 565 | 566 | (defun asech (z) 567 | (ln (add 568 | (mult 569 | (sqrt (sub 570 | (div (one) z) 571 | (one))) 572 | (sqrt (add 573 | (div (one) z) 574 | (one)))) 575 | (div (one) z)))) 576 | 577 | (defun acoth (z) 578 | (add 579 | (div (ln (sub (one) 580 | (div (one) z))) 581 | (-two)) 582 | (div (ln (add (one) 583 | (div (one) z))) 584 | (two)))) 585 | 586 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 587 | ;;; Polar Functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 588 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 589 | 590 | (defun r (z-polar) 591 | (complex-polar-mod z-polar)) 592 | 593 | (defun distance (z-polar) 594 | (r z-polar)) 595 | 596 | (defun phi (z-polar) 597 | (complex-polar-arg z-polar)) 598 | 599 | (defun angle (z-polar) 600 | (phi z-polar)) 601 | 602 | (defun rect->polar (z) 603 | (new-polar (modulus z) 604 | (arg z))) 605 | 606 | (defun polar->rect 607 | (((= (match-complex-polar) polar)) 608 | (polar->rect (r polar) 609 | (phi polar))) 610 | ((phi) 611 | (polar->rect 1 phi))) 612 | 613 | (defun polar->rect (r phi) 614 | (new (* r (math:cos phi)) 615 | (* r (math:sin phi)))) 616 | 617 | (defun complex? (z) 618 | (is-complex z)) 619 | 620 | (defun complex-polar? (z-polar) 621 | (is-complex-polar z-polar)) 622 | 623 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 624 | ;;; Display ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 625 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 626 | 627 | ;; Pretty-print: 628 | ;; 629 | ;; lfe> (complex:format c1) 630 | ;; 1+2i 631 | ;; ok 632 | ;; lfe> (complex:format c2) 633 | ;; 3-5i 634 | ;; ok 635 | 636 | (defun format 637 | (((= (match-complex) z)) 638 | (io:format (++ (cmplx-util:->str z) "~n"))) 639 | (((= (match-complex-polar) polar)) 640 | (format (polar->rect polar))) 641 | ((x) 642 | (io:format "~p~n" (list x)))) 643 | -------------------------------------------------------------------------------- /test/unit-cmplx-arith-tests.lfe: -------------------------------------------------------------------------------- 1 | (defmodule unit-cmplx-arith-tests 2 | (behaviour ltest-unit) 3 | (export all)) 4 | 5 | (include-lib "ltest/include/ltest-macros.lfe") 6 | 7 | (deftest add 8 | (is-equal #(complex 4 -3) 9 | (complex:add (unit-cmplx-tests:c1) 10 | (unit-cmplx-tests:c2))) 11 | (is-equal #(complex -5 -2) 12 | (complex:add (unit-cmplx-tests:c3) 13 | (unit-cmplx-tests:c4)))) 14 | 15 | (deftest sub 16 | (is-equal #(complex -2 7) 17 | (complex:sub (unit-cmplx-tests:c1) 18 | (unit-cmplx-tests:c2))) 19 | (is-equal #(complex 3 2) 20 | (complex:sub (unit-cmplx-tests:c3) 21 | (unit-cmplx-tests:c4)))) 22 | 23 | (deftest mult 24 | (is-equal #(complex 13 1) 25 | (complex:mult (unit-cmplx-tests:c1) 26 | (unit-cmplx-tests:c2))) 27 | (is-equal #(complex 4 2) 28 | (complex:mult (unit-cmplx-tests:c3) 29 | (unit-cmplx-tests:c4)))) 30 | 31 | (deftest div 32 | (is-equal #(complex 1.0 0.0) 33 | (complex:div (unit-cmplx-tests:c1) 34 | (unit-cmplx-tests:c1))) 35 | (is-equal #(complex 1.0 0.0) 36 | (complex:div (unit-cmplx-tests:c4) 37 | (unit-cmplx-tests:c4))) 38 | (is-equal #(complex -0.1 1.3) 39 | (complex:div (unit-cmplx-tests:c2) 40 | (unit-cmplx-tests:c4))) 41 | (is-equal #(complex 0.2 -0.1) 42 | (complex:div (unit-cmplx-tests:c3) 43 | (unit-cmplx-tests:c4)))) -------------------------------------------------------------------------------- /test/unit-cmplx-exp-tests.lfe: -------------------------------------------------------------------------------- 1 | (defmodule unit-cmplx-exp-tests 2 | (behaviour ltest-unit) 3 | (export all)) 4 | 5 | (include-lib "ltest/include/ltest-macros.lfe") 6 | 7 | (defun z1 () (complex:new 2 0)) 8 | (defun z2 () (complex:new 2 1)) 9 | 10 | (deftest pow-real 11 | (is (complex:eq #(complex 1 0) 12 | (complex:pow (z1) 0))) 13 | (is (complex:eq #(complex 2 0) 14 | (complex:pow (z1) 1))) 15 | (is (complex:eq #(complex 4 0) 16 | (complex:pow (z1) 2))) 17 | (is (complex:eq #(complex 8 0) 18 | (complex:pow (z1) 3))) 19 | (is (complex:eq #(complex 16 0) 20 | (complex:pow (z1) 4)))) 21 | 22 | (deftest pow-img 23 | (is (complex:eq #(complex 1 0) 24 | (complex:pow (complex:i) 0))) 25 | (is (complex:eq #(complex 0 1) 26 | (complex:pow (complex:i) 1))) 27 | (is (complex:eq #(complex -1 0) 28 | (complex:pow (complex:i) 2))) 29 | (is (complex:eq #(complex 0 -1) 30 | (complex:pow (complex:i) 3))) 31 | (is (complex:eq #(complex 1 0) 32 | (complex:pow (complex:i) 4)))) 33 | 34 | (deftest pow-cmplx 35 | (is (complex:eq #(complex 1 0) 36 | (complex:pow (z2) 0))) 37 | (is (complex:eq #(complex 2 1) 38 | (complex:pow (z2) 1))) 39 | (is (complex:eq #(complex 3 4) 40 | (complex:pow (z2) 2))) 41 | (is (complex:eq #(complex 2 11) 42 | (complex:pow (z2) 3))) 43 | (is (complex:eq #(complex -7 24) 44 | (complex:pow (z2) 4)))) 45 | 46 | ;; XXX failing! 47 | (deftest pow-cmplx-negative 48 | (is (complex:eq #(complex 0.4 -0.2) 49 | (complex:pow (z2) -1))) 50 | (is (complex:eq #(complex 0.12 -0.16) 51 | (complex:pow (z2) -2))) 52 | (is (complex:eq #(complex 0.016 -0.088) 53 | (complex:pow (z2) -3))) 54 | (is (complex:eq #(complex -0.0112 -0.0384) 55 | (complex:pow (z2) -4)))) 56 | 57 | (deftest pow-roots 58 | (is (complex:eq #(complex 1.455346690225355 0.34356074972251255) 59 | (complex:pow (z2) 0.5))) 60 | (is (complex:eq #(complex 1.3560696537818155 0.2544190103116233) 61 | (complex:pow (z2) 0.4))) 62 | (is (complex:eq #(complex 1.2607549678168408 0.1765035631875992) 63 | (complex:pow (z2) 0.3))) 64 | (is (complex:eq #(complex 1.169572425128737 0.10876582110065519) 65 | (complex:pow (z2) 0.2))) 66 | (is (complex:eq #(complex 1.0826336795557296 0.05023205131826696) 67 | (complex:pow (z2) 0.1)))) 68 | 69 | (deftest pow-real-only 70 | (is (complex:eq #(complex 16 0) 71 | (complex:pow 4 2)))) 72 | 73 | (deftest exp 74 | (is (complex:eq #(complex 2.718281828459045 0) 75 | (complex:exp (complex:one)))) 76 | (is (complex:eq #(complex 0.5403023058681398 0.8414709848078965) 77 | (complex:exp (complex:i))))) 78 | 79 | (deftest ln 80 | (is (complex:eq #(complex 0.0 1.5707963267948966) 81 | (complex:ln (complex:i)))) 82 | (is (complex:eq #(complex 0.0 0.0) 83 | (complex:ln (complex:one)))) 84 | (is (complex:eq #(complex 0.6931471805599453 0.0) 85 | (complex:ln (z1))))) 86 | ;; XXX failing! 87 | (deftest exp-ln-equality 88 | (is (complex:eq (complex:i) 89 | (complex:ln 90 | (complex:exp 91 | (complex:i))))) 92 | (is (complex:eq (complex:i) 93 | (complex:exp 94 | (complex:ln 95 | (complex:i))) 96 | '(#(tol 1.0e-15))))) -------------------------------------------------------------------------------- /test/unit-cmplx-ops-tests.lfe: -------------------------------------------------------------------------------- 1 | (defmodule unit-cmplx-ops-tests 2 | (behaviour ltest-unit) 3 | (export all)) 4 | 5 | (include-lib "ltest/include/ltest-macros.lfe") 6 | 7 | (deftest eq 8 | (is (complex:eq (unit-cmplx-tests:c1) 9 | (unit-cmplx-tests:c1))) 10 | (is (complex:eq (unit-cmplx-tests:c2) 11 | (unit-cmplx-tests:c2))) 12 | (is-not (complex:eq (unit-cmplx-tests:c1) 13 | (unit-cmplx-tests:c2))) 14 | (is-not (complex:eq (unit-cmplx-tests:c3) 15 | (unit-cmplx-tests:c4)))) 16 | 17 | (deftest conj 18 | (is-equal #(complex 1 -2) (complex:conj (unit-cmplx-tests:c1))) 19 | (is-equal #(complex 3 5) (complex:conj (unit-cmplx-tests:c2))) 20 | (is-equal #(complex -1 0) (complex:conj (unit-cmplx-tests:c3))) 21 | (is-equal #(complex -4 2) (complex:conj (unit-cmplx-tests:c4))) 22 | (is-equal #(complex 0 -5) (complex:conj (unit-cmplx-tests:c7)))) 23 | 24 | (deftest modsq 25 | (is-equal #(complex 5 0) (complex:modsq (unit-cmplx-tests:c1))) 26 | (is-equal #(complex 34 0) (complex:modsq (unit-cmplx-tests:c2))) 27 | (is-equal #(complex 1 0) (complex:modsq (unit-cmplx-tests:c3))) 28 | (is-equal #(complex 20 0) (complex:modsq (unit-cmplx-tests:c4))) 29 | (is-equal #(complex 25 0) (complex:modsq (unit-cmplx-tests:c7)))) 30 | 31 | (deftest abs 32 | (is-equal 2.23606797749979 (complex:abs (unit-cmplx-tests:c1))) 33 | (is-equal 5.830951894845301 (complex:abs (unit-cmplx-tests:c2))) 34 | (is-equal 1.0 (complex:abs (unit-cmplx-tests:c3))) 35 | (is-equal 4.47213595499958 (complex:abs (unit-cmplx-tests:c4)))) 36 | 37 | ;; XXX failing! 38 | (deftest inv 39 | ;(is-equal #(complex 0.2 -0.4) (complex:inv (unit-cmplx-tests:c1))) 40 | (is-equal #(complex 0.2 -0.4) (complex:inv (unit-cmplx-tests:c2))) 41 | ;(is-equal #(complex -1.0 0.0) (complex:inv (unit-cmplx-tests:c3))) 42 | ;(is-equal #(complex -0.2 0.1) (complex:inv (unit-cmplx-tests:c4))) 43 | ) 44 | 45 | (deftest sqrt 46 | (is-equal #(complex 1.272019649514069 0.7861513777574233) 47 | (complex:sqrt (unit-cmplx-tests:c1))) 48 | (is-equal #(complex 2.101303392521568 -1.1897377641407583) 49 | (complex:sqrt (unit-cmplx-tests:c2))) 50 | (is-equal #(complex 0.0 1.0) 51 | (complex:sqrt (unit-cmplx-tests:c3))) 52 | (is-equal #(complex 0.48586827175664576 -2.0581710272714924) 53 | (complex:sqrt (unit-cmplx-tests:c4)))) -------------------------------------------------------------------------------- /test/unit-cmplx-polar-tests.lfe: -------------------------------------------------------------------------------- 1 | (defmodule unit-cmplx-polar-tests 2 | (behaviour ltest-unit) 3 | (export all)) 4 | 5 | (include-lib "ltest/include/ltest-macros.lfe") 6 | 7 | ;; XXX failing! 8 | (deftest polar->rect 9 | (is (complex:eq #(complex 0 1) 10 | (complex:polar->rect (/ (math:pi) 2)) 11 | '(#(tol 1e-15)))) 12 | (is (complex:eq #(complex 0 -1) 13 | (complex:polar->rect -1 (/ (math:pi) 2)) 14 | '(#(tol 1e-15)))) 15 | (is (complex:eq #(complex -1 0) 16 | (complex:polar->rect (math:pi)) 17 | '(#(tol 1e-15)))) 18 | (is (complex:eq #(complex 1 0) 19 | (complex:polar->rect -1 (math:pi)) 20 | '(#(tol 1e-15))))) 21 | 22 | (deftest rect->polar 23 | (is (complex:eq `#(complex-polar 1 ,(/ (math:pi) 2)) 24 | (complex:rect->polar (complex:new 0 1))))) -------------------------------------------------------------------------------- /test/unit-cmplx-tests.lfe: -------------------------------------------------------------------------------- 1 | (defmodule unit-cmplx-tests 2 | (behaviour ltest-unit) 3 | (export all)) 4 | 5 | (include-lib "ltest/include/ltest-macros.lfe") 6 | 7 | (defun c1 () (complex:new 1 2)) 8 | (defun c2 () (complex:new 3 -5)) 9 | (defun c3 () (complex:new -1 0)) 10 | (defun c4 () (complex:new -4 -2)) 11 | (defun c5 () (complex:new)) 12 | (defun c6 () (complex:new 4)) 13 | (defun c7 () (complex:new 0 5)) 14 | (defun c8 () (complex:new 1 1)) 15 | (defun c9 () (complex:new 0 -5)) 16 | (defun c10 () (complex:new 1 0)) 17 | 18 | (deftest mew-no-args 19 | (is-equal #(complex 0 0) (c5))) 20 | 21 | (deftest new-basic 22 | (is-equal (c1) (complex:new "1+2i")) 23 | (is-equal (c2) (complex:new "3-5i")) 24 | (is-equal (c1) (complex:new '1+2i)) 25 | (is-equal (c2) (complex:new '3-5i)) 26 | (is-equal #(complex -4 -2) (c4)) 27 | (is-equal (c4) (complex:new '-4-2i))) 28 | 29 | (deftest new-no-img 30 | (is-equal #(complex 4 0) (c6)) 31 | (is-equal (c10) (complex:new "1"))) 32 | 33 | (deftest new-no-img-plus-sign 34 | (is-equal (c10) (complex:new "+1")) 35 | (is-equal (c10) (complex:new "+1+0i"))) 36 | 37 | (deftest new-no-img-minus-sign 38 | (is-equal (c3) (complex:new "-1")) 39 | (is-equal (c3) (complex:new '-1))) 40 | 41 | (deftest new-no-real 42 | (is-equal #(complex 0 2) (complex:new "0+2i")) 43 | (is-equal #(complex 0 2) (complex:new '0+2i)) 44 | (is-equal (c7) (complex:new "5i")) 45 | (is-equal (c7) (complex:new '5i)) 46 | (is-equal (c9) (complex:new "0-5i"))) 47 | 48 | (deftest new-no-real-plus-sign 49 | (is-equal (c7) (complex:new "+5i")) 50 | (is-equal (c7) (complex:new '+5i)) 51 | (is-equal (c7) (complex:new "+0+5i"))) 52 | 53 | (deftest new-no-real-minus-sign 54 | (is-equal (c9) (complex:new "-5i")) 55 | (is-equal (c9) (complex:new '-5i)) 56 | (is-equal (c9) (complex:new "-0-5i")) 57 | (is-equal (c9) (complex:new "+0-5i"))) 58 | -------------------------------------------------------------------------------- /test/unit-cmplx-trig-tests.lfe: -------------------------------------------------------------------------------- 1 | (defmodule unit-cmplx-trig-tests 2 | (behaviour ltest-unit) 3 | (export all)) 4 | 5 | (include-lib "ltest/include/ltest-macros.lfe") 6 | 7 | (defun z1 () 8 | (complex:new (math:pi) 1)) 9 | 10 | (defun z2 () 11 | (complex:new 1 (/ (math:pi) 2))) 12 | 13 | ;; Trigonometric functions 14 | 15 | ;; !!! 16 | ;; XXX failing! ALL OF THESE!!! 17 | 18 | (deftest sin 19 | (is (complex:eq #(complex 0 -1.1752011936438014) 20 | (complex:sin (z1)) 21 | '(#(tol 1.0e-15))))) 22 | 23 | (deftest cos 24 | (is (complex:eq #(complex -1.5430806348152437 0) 25 | (complex:cos (z1)) 26 | '(#(tol 1.0e-15))))) 27 | 28 | (deftest tan 29 | (is (complex:eq #(complex 0 0.7615941559557649) 30 | (complex:tan (z1)) 31 | '(#(tol 1.0e-15))))) 32 | 33 | (deftest csc 34 | (is (complex:eq #(complex 0 0.8509181282393217) 35 | (complex:csc (z1)) 36 | '(#(tol 1.0e-15))))) 37 | 38 | (deftest sec 39 | (is (complex:eq #(complex -0.6480542736638853 0) 40 | (complex:sec (z1)) 41 | '(#(tol 1.0e-15))))) 42 | 43 | (deftest cot 44 | (is (complex:eq #(complex 0 -1.3130352854993315) 45 | (complex:cot (z1)) 46 | '(#(tol 1.0e-15))))) 47 | 48 | ;; Hyperbolic trigonometric functions 49 | 50 | (deftest sinh 51 | (is (complex:eq #(complex 0 1.5430806348152437) 52 | (complex:sinh (z2)) 53 | '(#(tol 1.0e-15))))) 54 | 55 | (deftest cosh 56 | (is (complex:eq #(complex 0 -1.1752011936438014) 57 | (complex:cosh (z2)) 58 | '(#(tol 1.0e-15))))) 59 | 60 | (deftest tanh 61 | (is (complex:eq #(complex -1.3130352854993315 0) 62 | (complex:tanh (z2)) 63 | '(#(tol 1.0e-15))))) 64 | 65 | (deftest csch 66 | (is (complex:eq #(complex 0 -0.6480542736638853) 67 | (complex:csch (z2)) 68 | '(#(tol 1.0e-15))))) 69 | 70 | (deftest sech 71 | (is (complex:eq #(complex 0 0.8509181282393217) 72 | (complex:sech (z2)) 73 | '(#(tol 1.0e-15))))) 74 | 75 | (deftest coth 76 | (is (complex:eq #(complex -0.7615941559557649 0) 77 | (complex:coth (z2)) 78 | '(#(tol 1.0e-15))))) 79 | 80 | ;; Inverse trigonometric functions 81 | 82 | (deftest asin 83 | (is (complex:eq #(complex 0.5076856578639746 1.3492323556536476) 84 | (complex:asin (z2)) 85 | '(#(tol 1.0e-15))))) 86 | 87 | (deftest acos 88 | (is (complex:eq #(complex 1.0631106689309222 -1.349232355653647) 89 | (complex:acos (z2)) 90 | '(#(tol 1.0e-15))))) 91 | 92 | (deftest atan 93 | (is (complex:eq #(complex 1.2302200294351602 0.43682712862323564) 94 | (complex:atan (z2)) 95 | '(#(tol 1.0e-15))))) 96 | 97 | (deftest acsc 98 | (is (complex:eq #(complex 0.2641409023818012 -0.45358107907660455) 99 | (complex:acsc (z2)) 100 | '(#(tol 1.0e-15))))) 101 | 102 | (deftest asec 103 | (is (complex:eq #(complex 1.3066554244130952 0.45358107907660455) 104 | (complex:asec (z2)) 105 | '(#(tol 1.0e-15))))) 106 | 107 | (deftest acot 108 | (is (complex:eq #(complex 0.34057629735973644 -0.4368271286232357) 109 | (complex:acot (z2)) 110 | '(#(tol 1.0e-15))))) 111 | 112 | ;; Inverse hyperbolic trigonometric functions 113 | 114 | (deftest asinh 115 | (is (complex:eq #(complex 1.290542097300704 0.9331538843123816) 116 | (complex:asinh (z2)) 117 | '(#(tol 1.0e-15))))) 118 | 119 | (deftest acosh 120 | (is (complex:eq #(complex 1.349232355653647 1.0631106689309222) 121 | (complex:acosh (z2)) 122 | '(#(tol 1.0e-15))))) 123 | 124 | (deftest atanh 125 | (is (complex:eq #(complex 0.2409022331451228 1.1182850384116252) 126 | (complex:atanh (z2)) 127 | '(#(tol 1.0e-15))))) 128 | 129 | (deftest acsch 130 | (is (complex:eq #(complex 0.3144855040543597 -0.4461590911371423) 131 | (complex:acsch (z2)) 132 | '(#(tol 1.0e-15))))) 133 | 134 | (deftest asech 135 | (is (complex:eq #(complex 0.45358107907660455 -1.3066554244130952) 136 | (complex:asech (z2)) 137 | '(#(tol 1.0e-15))))) 138 | 139 | (deftest acoth 140 | (is (complex:eq #(complex 0.24090223314512274 -0.45251128838327137) 141 | (complex:acoth (z2)) 142 | '(#(tol 1.0e-15))))) -------------------------------------------------------------------------------- /test/unit-cmplx-util-tests.lfe: -------------------------------------------------------------------------------- 1 | (defmodule unit-cmplx-util-tests 2 | (behaviour ltest-unit) 3 | (export all)) 4 | 5 | (include-lib "ltest/include/ltest-macros.lfe") 6 | 7 | (deftest ->str 8 | (is-equal '("1" "+" "2" #\i) 9 | (cmplx-util:->str (unit-cmplx-tests:c1))) 10 | (is-equal '("3" "" "-5" #\i) 11 | (cmplx-util:->str (unit-cmplx-tests:c2))) 12 | (is-equal '("-1" "+" "0" #\i) 13 | (cmplx-util:->str (unit-cmplx-tests:c3))) 14 | (is-equal '("-4" "" "-2" #\i) 15 | (cmplx-util:->str (unit-cmplx-tests:c4))) 16 | (is-equal '("0" "+" "5" #\i) 17 | (cmplx-util:->str (unit-cmplx-tests:c7)))) 18 | 19 | (deftest str->real 20 | (is-equal #(complex 1 0) (cmplx-util:str-> "1")) 21 | (is-equal #(complex 10 0) (cmplx-util:str-> "10")) 22 | (is-equal #(complex -1 0) (cmplx-util:str-> "-1")) 23 | (is-equal #(complex -10 0) (cmplx-util:str-> "-10")) 24 | (is-equal #(complex 1 0) (cmplx-util:str-> "+1")) 25 | (is-equal #(complex 10 0) (cmplx-util:str-> "+10")) 26 | (is-equal #(complex 1.2 0) (cmplx-util:str-> "1.2")) 27 | (is-equal #(complex 1.2e200 0) (cmplx-util:str-> "1.2e200")) 28 | (is-equal #(complex 1.2e200 0) (cmplx-util:str-> "1.2e+200")) 29 | (is-equal #(complex 1.2e-200 0) (cmplx-util:str-> "1.2e-200")) 30 | (is-equal #(complex 1.2e200 0) (cmplx-util:str-> "1.2E200")) 31 | (is-equal #(complex 1.2e200 0) (cmplx-util:str-> "1.2E+200")) 32 | (is-equal #(complex 1.2e-200 0) (cmplx-util:str-> "1.2E-200"))) 33 | 34 | (deftest str->img 35 | (is-equal #(complex 0 1) (cmplx-util:str-> "0+1i")) 36 | (is-equal #(complex 0 10) (cmplx-util:str-> "0+10i")) 37 | (is-equal #(complex 0 -1) (cmplx-util:str-> "0-1i")) 38 | (is-equal #(complex 0 -10) (cmplx-util:str-> "0-10i")) 39 | (is-equal #(complex 0 1.2) (cmplx-util:str-> "0+1.2i")) 40 | (is-equal #(complex 0 1.2e200) (cmplx-util:str-> "0+1.2e200i")) 41 | (is-equal #(complex 0 1.2e200) (cmplx-util:str-> "0+1.2e+200i")) 42 | (is-equal #(complex 0 1.2e-200) (cmplx-util:str-> "0+1.2e-200i")) 43 | (is-equal #(complex 0 1) (cmplx-util:str-> "0+1j")) 44 | (is-equal #(complex 0 2) (cmplx-util:str-> "0+2I")) 45 | (is-equal #(complex 0 3) (cmplx-util:str-> "0+3J"))) 46 | 47 | (deftest str->complex 48 | (is-equal #(complex 4 2) (cmplx-util:str-> "4+2i")) 49 | (is-equal #(complex -4 -2) (cmplx-util:str-> "-4-2i")) 50 | (is-equal #(complex 4 2) (cmplx-util:str-> "+4+2i")) 51 | (is-equal #(complex 1.2 -3.4) (cmplx-util:str-> "1.2-3.4i")) 52 | (is-equal #(complex 1.2e3 -4.5e-6) (cmplx-util:str-> "1.2e3-4.5e-6i"))) 53 | --------------------------------------------------------------------------------