Skip to content

Commit

Permalink
Merge pull request #66 from barucden/em-overhaul
Browse files Browse the repository at this point in the history
Clean-up
  • Loading branch information
barucden authored Oct 15, 2024
2 parents 490309b + 5348022 commit 398e636
Show file tree
Hide file tree
Showing 13 changed files with 147 additions and 169 deletions.
25 changes: 0 additions & 25 deletions .travis.yml

This file was deleted.

2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ uuid = "abce61dc-4473-55a0-ba07-351d65e31d42"
version = "0.4.1"

[compat]
julia = "0.7, 1"
julia = "1"

[extras]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Expand Down
45 changes: 23 additions & 22 deletions src/Decimals.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,36 @@
# @author [email protected] (Jack Peterson), 7/3/2014

module Decimals
import Base: ==, +, -, *, /, <, <=, float, inv, round, trunc

export Decimal,
decimal,
number,
normalize
export Decimal,
decimal,
number,
normalize

const DIGITS = 20
const DIGITS = 20

# Numerical value: (-1)^s * c * 10^q
struct Decimal <: AbstractFloat
s::Integer # sign can be 0 (+) or 1 (-)
c::BigInt # coefficient (significand), must be non-negative
q::Integer # exponent
end
# Numerical value: (-1)^s * c * 10^q
struct Decimal <: AbstractFloat
s::Bool # sign can be 0 (+) or 1 (-)
c::BigInt # coefficient (significand), must be non-negative
q::Int # exponent

# Convert between Decimal objects, numbers, and strings
include("decimal.jl")
Decimal(s::Integer, c::Integer, e::Integer) = new(Bool(s), c, e)
end

# Convert between Decimal objects, numbers, and strings
include("decimal.jl")

# Decimal normalization
include("norm.jl")
# Decimal normalization
include("norm.jl")

# Addition, subtraction, negation, multiplication
include("arithmetic.jl")
# Addition, subtraction, negation, multiplication
include("arithmetic.jl")

# Equality
include("equals.jl")
# Equality
include("equals.jl")

# Rounding
include("round.jl")
# Rounding
include("round.jl")

end
14 changes: 7 additions & 7 deletions src/arithmetic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const BigTen = BigInt(10)
# To add, convert both decimals to the same exponent.
# (If the exponents are different, use the smaller exponent
# to make sure we're adding integers.)
function +(x::Decimal, y::Decimal)
function Base.:(+)(x::Decimal, y::Decimal)
if x.q < y.q
x, y = y, x
end
Expand All @@ -25,25 +25,25 @@ function +(x::Decimal, y::Decimal)
end

# Negation
-(x::Decimal) = Decimal((x.s == 1) ? 0 : 1, x.c, x.q)
Base.:(-)(x::Decimal) = Decimal(!x.s, x.c, x.q)

# Subtraction
-(x::Decimal, y::Decimal) = +(x, -y)
Base.:(-)(x::Decimal, y::Decimal) = +(x, -y)

# Multiplication
function *(x::Decimal, y::Decimal)
s = (x.s == y.s) ? 0 : 1
function Base.:(*)(x::Decimal, y::Decimal)
s = x.s != y.s
normalize(Decimal(s, BigInt(x.c) * BigInt(y.c), x.q + y.q))
end

# Inversion
function Base.inv(x::Decimal)
c = round(BigInt(10)^(-x.q + DIGITS) / x.c) # the decimal point of 1/x.c is shifted by -x.q so that the integer part of the result is correct and then it is shifted further by DIGITS to also cover some digits from the fractional part.
c = round(BigInt, BigInt(10)^(-x.q + DIGITS) / x.c) # the decimal point of 1/x.c is shifted by -x.q so that the integer part of the result is correct and then it is shifted further by DIGITS to also cover some digits from the fractional part.
q = -DIGITS # we only need to remember that there are these digits after the decimal point
normalize(Decimal(x.s, c, q))
end

# Division
/(x::Decimal, y::Decimal) = x * inv(y)
Base.:(/)(x::Decimal, y::Decimal) = x * inv(y)

# TODO exponentiation
13 changes: 8 additions & 5 deletions src/decimal.jl
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
# Convert a string to a decimal, e.g. "0.01" -> Decimal(0, 1, -2)
function Base.parse(::Type{Decimal}, str::AbstractString)
if 'e' in str
if 'e' str
return parse(Decimal, scinote(str))
elseif 'E' str
return parse(Decimal, scinote(lowercase(str)))
end
c, q = parameters(('.' in str) ? split(str, '.') : str)
normalize(Decimal((str[1] == '-') ? 1 : 0, c, q))
normalize(Decimal(str[1] == '-', c, q))
end

decimal(str::AbstractString) = parse(Decimal, str)
Expand Down Expand Up @@ -60,8 +62,8 @@ function Base.print(io::IO, x::Decimal)
end

# Zero/one value
Base.zero(::Type{Decimal}) = Decimal(0,0,0)
Base.one(::Type{Decimal}) = Decimal(0,1,0)
Base.zero(::Type{Decimal}) = Decimal(false, 0, 0)
Base.one(::Type{Decimal}) = Decimal(false, 1, 0)

# convert a decimal to any subtype of Real
(::Type{T})(x::Decimal) where {T<:Real} = parse(T, string(x))
Expand All @@ -73,4 +75,5 @@ function number(x::Decimal)
end

# sign
Base.signbit(x::Decimal) = x.s != 0
Base.signbit(x::Decimal) = x.s

8 changes: 4 additions & 4 deletions src/equals.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# equals() now depends on == instead
# of the other way round.
function ==(x::Decimal, y::Decimal)
function Base.:(==)(x::Decimal, y::Decimal)
# return early on zero
x_is_zero = iszero(x)
y_is_zero = iszero(y)
Expand All @@ -17,7 +17,7 @@ end

Base.iszero(x::Decimal) = iszero(x.c)

function <(x::Decimal, y::Decimal)
function Base.:(<)(x::Decimal, y::Decimal)
# return early on zero
if iszero(x) && iszero(y)
return false
Expand Down Expand Up @@ -46,8 +46,8 @@ end
# Special case equality with AbstractFloat to allow comparison against Inf/Nan
# which are not representable in Decimal

==(a::AbstractFloat, b::Decimal) = b == a
function ==(a::Decimal, b::AbstractFloat)
Base.:(==)(a::AbstractFloat, b::Decimal) = b == a
function Base.:(==)(a::Decimal, b::AbstractFloat)
# Decimal does not represent NaN/Inf
(isinf(b) || isnan(b)) && return false
==(promote(a, b)...)
Expand Down
4 changes: 2 additions & 2 deletions src/round.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Rounding
function round(x::Decimal; digits::Int=0, normal::Bool=false)
function Base.round(x::Decimal; digits::Int=0, normal::Bool=false)
shift = BigInt(digits) + x.q
if shift > BigInt(0) || shift < x.q
(normal) ? x : normalize(x, rounded=true)
Expand All @@ -10,7 +10,7 @@ function round(x::Decimal; digits::Int=0, normal::Bool=false)
end
end

function trunc(x::Decimal; digits::Int=0, normal::Bool=false)
function Base.trunc(x::Decimal; digits::Int=0, normal::Bool=false)
shift = BigInt(digits) + x.q
if shift > BigInt(0) || shift < x.q
(normal) ? x : normalize(x, rounded=true)
Expand Down
12 changes: 6 additions & 6 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ using Test
@testset "Decimals" begin

global d = [
Decimal(0, 2, -1)
Decimal(0, 1, -1)
Decimal(0, 100, -4)
Decimal(0, 1512, -2)
Decimal(1, 3, -2)
Decimal(1, 4, -6)
Decimal(false, 2, -1)
Decimal(false, 1, -1)
Decimal(false, 100, -4)
Decimal(false, 1512, -2)
Decimal(true, 3, -2)
Decimal(true, 4, -6)
]

include("test_constructor.jl")
Expand Down
21 changes: 10 additions & 11 deletions test/test_arithmetic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ using Test
@test Decimal(0.1) + 0.2 == 0.1 + Decimal(0.2) == Decimal(0.1) + Decimal(0.2) == Decimal(0.3)
@test Decimal.([0.1 0.2]) .+ [0.3 0.1] == Decimal.([0.4 0.3])
@test Decimal(2147483646) + Decimal(1) == Decimal(2147483647)
@test Decimal(1,3,-2) + parse(Decimal, "0.2523410412138103") == Decimal(0,2223410412138103,-16)

@test Decimal(1,3,-2) + parse(Decimal, "0.2523410412138103") == Decimal(false,2223410412138103,-16)
@test Decimal(0, 10000000000000000001, -19) + Decimal(0, 1, 0) == Decimal(0, 20000000000000000001, -19)
end

Expand Down Expand Up @@ -40,15 +39,15 @@ end
end

@testset "Inversion" begin
@test inv(Decimal(0, 1, -1)) == Decimal(0, 1, 1)
@test inv(Decimal(0, 1, 1)) == Decimal(0, 1, -1)
@test inv(Decimal(1, 2, -1)) == Decimal(1, 5, 0)
@test inv(Decimal(1, 5, 0)) == Decimal(1, 2, -1)
@test inv(Decimal(0, 2, -2)) == Decimal(0, 5, 1)
@test inv(Decimal(0, 5, 1)) == Decimal(0, 2, -2)
@test inv(Decimal(1, 4, -1)) == Decimal(1, 25, -1)
@test inv(Decimal(1, 25, -1)) == Decimal(1, 4, -1)
@test inv(Decimal(0, 123, -1)) == Decimal(0, 813008130081300813, -19) # 1/12.3 ≈ 0.08
@test inv(Decimal(false, 1, -1)) == Decimal(false, 1, 1)
@test inv(Decimal(false, 1, 1)) == Decimal(false, 1, -1)
@test inv(Decimal(true, 2, -1)) == Decimal(true, 5, 0)
@test inv(Decimal(true, 5, 0)) == Decimal(true, 2, -1)
@test inv(Decimal(false, 2, -2)) == Decimal(false, 5, 1)
@test inv(Decimal(false, 5, 1)) == Decimal(false, 2, -2)
@test inv(Decimal(true, 4, -1)) == Decimal(true, 25, -1)
@test inv(Decimal(true, 25, -1)) == Decimal(true, 4, -1)
@test inv(Decimal(false, 123, -1)) == Decimal(false, 813008130081300813, -19) # 1/12.3 ≈ 0.08
end

@testset "Division" begin
Expand Down
2 changes: 1 addition & 1 deletion test/test_constructor.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ using Test

@testset "Decimal constructor" begin

@test isa(d, Array{Decimal,1})
@test d isa Vector{Decimal}

end
Loading

0 comments on commit 398e636

Please sign in to comment.