Skip to content

Commit

Permalink
Make results of floor, trunc, ceil consistent (#76)
Browse files Browse the repository at this point in the history
  • Loading branch information
omus authored and TotalVerb committed May 13, 2017
1 parent c4181aa commit a67a636
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 4 deletions.
11 changes: 7 additions & 4 deletions src/FixedPointDecimals/FixedPointDecimals.jl
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,17 @@ function ceil{T, f}(x::FD{T, f})
end
end

for truncfn in [:trunc, :floor, :ceil]
@eval $truncfn{TI <: Integer}(::Type{TI}, x::FD)::TI = $truncfn(x)
for fn in [:trunc, :floor, :ceil]
@eval $fn{TI <: Integer}(::Type{TI}, x::FD)::TI = $fn(x)

# round/trunc/ceil/flooring to FD; generic
# TODO. this is probably incorrect for floating point and we need to check
# overflow in other cases.
@eval function $truncfn{T, f}(::Type{FD{T, f}}, x::Real)
reinterpret(FD{T, f}, $truncfn(T, T(10)^f * x))
@eval function $fn{T, f}(::Type{FD{T, f}}, x::Real)
powt = T(10)^f
val = trunc(T, x)
val = val * powt + $fn(T, (x - val) * powt)
reinterpret(FD{T, f}, val)
end
end
round{TI <: Integer}(::Type{TI}, x::FD,
Expand Down
40 changes: 40 additions & 0 deletions test/fixed-point.jl
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using Base.Test
using Compat
using Currencies.FixedPointDecimals
import Currencies.FixedPointDecimals: FD

const SFD2 = FixedDecimal{Int16, 2}
const SFD4 = FixedDecimal{Int16, 4}
const FD1 = FixedDecimal{Int, 1}
const FD2 = FixedDecimal{Int, 2}
const FD3 = FixedDecimal{Int, 3}
const FD4 = FixedDecimal{Int, 4}
const WFD2 = FixedDecimal{Int128, 2}
const WFD4 = FixedDecimal{Int128, 4}
Expand Down Expand Up @@ -37,12 +39,22 @@ const keyvalues = Dict(
reinterpret(WFD4, 164435910993133062409572187012743929911),
typemax(WFD4)])

# Floating point values written as integer strings. Useful for testing behaviours of
# trunc, floor, and ceil.
const INT_2_2 = "22000000000000001776356839400250464677" # 2.2
const INT_2_3 = "22999999999999998223643160599749535322" # 2.3


# numbers that may cause overflow
islarge(x) = x == typemin(x) || abs(x) > 1000

# numbers that can never cause overflow
issmall(x) = -1 < x 1

function parse_int{T, f}(::Type{FD{T, f}}, val::AbstractString; ceil::Bool=false)
reinterpret(FD{T, f}, parse(T, val[1:(f + 1)]) + T(ceil))
end

@testset "conversion" begin
@testset for x in keyvalues[FD2]
@testset for T in [Rational{Int128}, WFD2, WFD4]
Expand Down Expand Up @@ -285,6 +297,16 @@ end
@test isinteger(Base.widemul(10, FD2(trunc(FD1, x))))
@test abs(FD2(trunc(FD1, x))) 0
end

@testset "truncate precision" begin
@test trunc(FD2, 2.3) != trunc(FD3, 2.3)
@test trunc(FD2, 2.3) == FD2(2.29)
@test trunc(FD3, 2.3) == FD3(2.299)

for f in 0:12
trunc(FD{Int64, f}, 2.3) == parse_int(FD{Int64, f}, INT_2_3)
end
end
end

# eps that works for integers too
Expand All @@ -303,6 +325,24 @@ epsi{T}(::Type{T}) = eps(T)
@test ceil(T, x) - epsi(T) < x ceil(T, x)
end
end

@testset "floor, ceil precision" begin
@test floor(FD2, 2.3) != floor(FD3, 2.3)
@test floor(FD2, 2.3) == FD2(2.29)
@test floor(FD3, 2.3) == FD3(2.299)

for f in 0:12
floor(FD{Int64, f}, 2.3) == parse_int(FD{Int64, f}, INT_2_3)
end

@test ceil(FD2, 2.2) != ceil(FD3, 2.2)
@test ceil(FD2, 2.2) == FD2(2.21)
@test ceil(FD3, 2.2) == FD3(2.201)

for f in 0:12
ceil(FD{Int64, f}, 2.2) == parse_int(FD{Int64, f}, INT_2_2, ceil=true)
end
end
end

@testset "show" begin
Expand Down

0 comments on commit a67a636

Please sign in to comment.