From 91569e4ab6926c3605311004dfd10b59ffc88a1f Mon Sep 17 00:00:00 2001 From: Christopher Doris Date: Wed, 2 Oct 2019 18:59:37 +0100 Subject: [PATCH] general improvements --- Project.toml | 6 ++ README.md | 17 ++--- src/LogarithmicNumbers.jl | 15 +++- src/arithmetic.jl | 50 ++++++++++++- src/clogarithmic.jl | 31 ++++++++ src/constructors.jl | 69 ++++++++++++++---- src/distributions.jl | 6 +- src/io.jl | 10 ++- src/logarithmic.jl | 4 +- src/promotion.jl | 47 ++++++++++-- src/random.jl | 9 ++- src/statsfuns.jl | 2 +- src/types.jl | 32 ++++++--- src/ulogarithmic.jl | 3 + test/runtests.jl | 147 ++++++++++++++++++++++++++++++++++++++ 15 files changed, 396 insertions(+), 52 deletions(-) create mode 100644 src/clogarithmic.jl create mode 100644 test/runtests.jl diff --git a/Project.toml b/Project.toml index cff04d8..cb0ef9f 100644 --- a/Project.toml +++ b/Project.toml @@ -9,3 +9,9 @@ Requires = "ae029012-a4dd-5104-9daa-d747884805df" [compat] julia = "1.0" + +[extras] +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[targets] +test = ["Test"] diff --git a/README.md b/README.md index 42dc7ec..21c1092 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A [logarithmic number system](https://en.wikipedia.org/wiki/Logarithmic_number_system) for Julia. -Provides two subtypes of `Real`: the unsigned `ULogarithmic`, representing a positive number in log-space; and signed `Logarithmic` which additionally has a sign bit. +Provides the types `ULogarithmic`, `Logarithmic` and `CLogarithmic` for representing non-negative real numbers, real numbers and complex numbers in log-space. This is useful when numbers are too big or small to fit accurately into a `Float64` and you only really care about magnitude. @@ -38,18 +38,19 @@ julia> log(x) ## Documentation -Two main types are exported: -* Type `ULogarithmic{T}`, which represents a positive real number by its logarithm of type `T`. -* Type `Logarithmic{T}` (signed), which represents a real number by its absolute value as a `ULogarithmic{T}` and a sign bit. +Three main types are exported: +* Type `ULogarithmic{T}`, which represents a non-negative real number by its logarithm of type `T`. +* Type `Logarithmic{T}`, which represents a real number by its absolute value as a `ULogarithmic{T}` and a sign bit. +* Type `CLogarithmic{T}`, which represents a complex number by its absolute value as a `ULogarithmic{T}` and an angle of type `T`. -Also exports type aliases `ULogFloat64`, `LogFloat64`, `ULogFloat32`, `LogFloat32`, `ULogFloat16`, `LogFloat16`, `ULogBigFloat`, `LogBigFloat`. +Also exports type aliases `ULogFloat64`, `LogFloat64`, `CLogFloat64`, `ULogFloat32`, `LogFloat32`, `CLogFloat32`, `ULogFloat16`, `LogFloat16`, `CLogFloat16`, `ULogBigFloat`, `LogBigFloat`, `CLogBigFloat`. Features: -* `ULogarithmic(x)` and `Logarithmic(x)` represent the number `x`. -* `exp(ULogarithmic, x)` and `exp(Logarithmic, x)` represent `exp(x)` (and `x` can be huge). +* `ULogarithmic(x)` (and `Logarithmic(x)`, etc.) represents the number `x`. +* `exp(ULogarithmic, x)` represents `exp(x)` (and `x` can be huge). * Arithmetic: `+`, `-`, `*`, `/`, `^`, `inv`, `log`, `prod`, `sum`. * Comparisons: equality, ordering, `cmp`, `isless`. -* Random: `rand(ULogarithmic)` and `rand(Logarithmic)` produces a random number in the unit interval. +* Random: `rand(ULogarithmic)` is a random number in the unit interval. * Other functions: `float`, `big`, `unsigned` (converts `ULogarithmic` to `Logarithmic`), `signed` (vice versa), `widen`, `typemin`, `typemax`, `zero`, `one`, `iszero`, `isone`, `isinf`, `isfinite`, `isnan`, `sign`, `signbit`, `abs`, `nextfloat`, `prevfloat`, `write`, `read`. ## Interoperability with other packages diff --git a/src/LogarithmicNumbers.jl b/src/LogarithmicNumbers.jl index 2afb7c3..af7ada2 100644 --- a/src/LogarithmicNumbers.jl +++ b/src/LogarithmicNumbers.jl @@ -7,14 +7,21 @@ module LogarithmicNumbers using Requires, Random -import Base: exp, log, *, /, ^, inv, +, -, prod, sum, show, write, read, float, big, unsigned, signed, widen, typemin, typemax, zero, one, iszero, isone, isinf, isfinite, isnan, sign, signbit, abs, ==, <, ≤, cmp, isless, nextfloat, prevfloat, rand, promote_rule +import Base: + exp, log, *, /, ^, inv, +, -, prod, sum, angle, show, + write, read, float, big, unsigned, signed, widen, + typemin, typemax, zero, one, iszero, isone, isinf, + isfinite, isnan, sign, signbit, abs, ==, isequal, <, ≤, + cmp, isless, nextfloat, prevfloat, rand, promote_rule, + conj, real, imag -export AbstractLogarithmic, ULogarithmic, Logarithmic +export ULogarithmic, Logarithmic, CLogarithmic include("types.jl") include("constructors.jl") include("ulogarithmic.jl") include("logarithmic.jl") +include("clogarithmic.jl") include("promotion.jl") include("arithmetic.jl") include("random.jl") @@ -25,10 +32,12 @@ include("init.jl") for T in (Float64, Float32, Float16, BigFloat) ULogT = Symbol(:ULog, T) LogT = Symbol(:Log, T) + CLogT = Symbol(:CLog, T) @eval begin const $(ULogT) = $(ULogarithmic{T}) const $(LogT) = $(Logarithmic{T}) - export $(ULogT), $(LogT) + const $(CLogT) = $(CLogarithmic{T}) + export $(ULogT), $(LogT), $(CLogT) end end diff --git a/src/arithmetic.jl b/src/arithmetic.jl index 0f56d71..f7b7da7 100644 --- a/src/arithmetic.jl +++ b/src/arithmetic.jl @@ -1,4 +1,8 @@ -exp(x::ALog) = uexp(x) +# generic + +exp(x::AnyLog) = uexp(x) + +# ULogarithmic log(x::ULogarithmic) = x.log *(x::ULogarithmic{T}, y::ULogarithmic{T}, rest::ULogarithmic{T}...) where {T} = uexp(T, +(log.((x, y, rest...))...)) @@ -8,13 +12,15 @@ log(x::ULogarithmic) = x.log inv(x::ULogarithmic{T}) where {T} = uexp(T, -x.log) # +(x::ULogarithmic, y::ULogarithmic) = x.log ≥ y.log ? x * ULogarithmic(1 + float(y/x)) : y * ULogarithmic(float(x/y) + 1) +(x::ULogarithmic{T}, y::ULogarithmic{T}, rest::ULogarithmic{T}...) where {T} = _add(x, y, rest...) --(x::ULogarithmic{T}, y::ULogarithmic{T}) where {T} = (xlog=x.log; ylog=y.log; xlog_exp(A,x), xs))), prod(exp.(xs))) || @info("prod",A,xs) + @test _approx(_float(_prod(map(x->_exp(A,x), xs))), prod(exp.(xs))) + end + end + + @testset "sum" begin + for A in atypes, xs in vecs + if eltype(xs) <: AbstractFloat + @test _approx(_float(_sum(map(x->exp(A,x),xs))), sum(exp.(xs))) + else + # sum is not type-stable because typeof(xs[1]+xs[2]) != typeof(xs[1]). + # hence this test is the same as above but without the stability check. + # we don't promise type stability unless the base type is a float, so + # this isn't a broken test. + @test _approx(_float(sum(map(x->exp(A,x),xs))), sum(exp.(xs))) + end + end + end + +end \ No newline at end of file