Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Clean-up #66

Merged
merged 4 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 jack@tinybike.net (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