From 1b5024fdc67424f164ac88803e34382abc7c875a Mon Sep 17 00:00:00 2001 From: John M Kuhn Date: Tue, 19 May 2020 23:02:13 -0400 Subject: [PATCH 1/6] Int128 support --- src/DecFP.jl | 47 ++++++++++++++++++++++++++++++++++++++++++++++- test/runtests.jl | 2 +- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/DecFP.jl b/src/DecFP.jl index 07c8a78..4ce3295 100644 --- a/src/DecFP.jl +++ b/src/DecFP.jl @@ -476,6 +476,9 @@ for w in (32,64,128) end end + @eval Base.convert(::Type{$BID}, x::Int128) = $BID(string(x)) + @eval Base.convert(::Type{$BID}, x::UInt128) = $BID(string(x)) + for w′ in (8,16,32,64) for (i′, i′str) in (("Int$w′", "int$w′"), ("UInt$w′", "uint$w′")) Ti′ = eval(Symbol(i′)) @@ -490,6 +493,48 @@ for w in (32,64,128) end end + for i′ in (Int128, UInt128) + Ti′ = eval(Symbol(i′)) + @eval begin + function Base.trunc(::Type{$Ti′}, x::$BID) + x′ = trunc(x) + (x′ < $BID(typemin($Ti′)) || x′ > $BID(typemax($Ti′))) && throw(InexactError(:convert, $Ti′, x)) + s, e = sigexp(x′) + return flipsign(s * $Ti′(10)^e, x) + end + + function Base.floor(::Type{$Ti′}, x::$BID) + x′ = floor(x) + (x′ < $BID(typemin($Ti′)) || x′ > $BID(typemax($Ti′))) && throw(InexactError(:convert, $Ti′, x)) + s, e = sigexp(x′) + return flipsign(s * $Ti′(10)^e, x) + end + + function Base.ceil(::Type{$Ti′}, x::$BID) + x′ = ceil(x) + (x′ < $BID(typemin($Ti′)) || x′ > $BID(typemax($Ti′))) && throw(InexactError(:convert, $Ti′, x)) + s, e = sigexp(x′) + return flipsign(s * $Ti′(10)^e, x) + end + + function Base.round(::Type{$Ti′}, x::$BID, ::RoundingMode{:NearestTiesAway}) + x′ = round(x, RoundNearestTiesAway) + (x′ < $BID(typemin($Ti′)) || x′ > $BID(typemax($Ti′))) && throw(InexactError(:convert, $Ti′, x)) + s, e = sigexp(x′) + return flipsign(s * $Ti′(10)^e, x) + end + + function Base.convert(::Type{$Ti′}, x::$BID) + x != trunc(x) && throw(InexactError(:convert, $Ti′, x)) + (x < $BID(typemin($Ti′)) || x > $BID(typemax($Ti′))) && throw(InexactError(:convert, $Ti′, x)) + s, e = sigexp(x) + return flipsign(s * $Ti′(10)^e, x) + end + + Base.$(Symbol("$Ti′"))(x::$BID) = convert($Ti′, x) + end + end + @eval Base.bswap(x::$BID) = reinterpret($BID, bswap(x.x)) @eval Base.convert(::Type{Float16}, x::$BID) = convert(Float16, convert(Float32, x)) @eval Base.Float16(x::$BID) = convert(Float16, x) @@ -659,7 +704,7 @@ Base.convert(T::Type{F}, x::Unsigned) where {F<:DecimalFloatingPoint} = F(UInt64 Base.convert(T::Type{F}, x::Rational) where {F<:DecimalFloatingPoint} = F(x.num) / F(x.den) Base.convert(T::Type{F}, x::Float16) where {F<:DecimalFloatingPoint} = F(Float32(x)) promote_rule(::Type{F}, ::Type{Float16}) where {F<:DecimalFloatingPoint} = F -promote_rule(::Type{F}, ::Type{T}) where {F<:DecimalFloatingPoint,T<:Union{Int8,UInt8,Int16,UInt16,Int32,UInt32,Int64,UInt64}} = F +promote_rule(::Type{F}, ::Type{T}) where {F<:DecimalFloatingPoint,T<:Union{Int8,UInt8,Int16,UInt16,Int32,UInt32,Int64,UInt64,Int128,UInt128}} = F # so that mathconsts get promoted to Dec32, not Dec64, like Float32 promote_rule(::Type{Irrational{s}}, ::Type{F}) where {s,F<:DecimalFloatingPoint} = F diff --git a/test/runtests.jl b/test/runtests.jl index ede000f..a5f4868 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -321,7 +321,7 @@ for T in (Dec32, Dec64, Dec128) @test round(T(2.5), RoundNearestTiesAway) === round(T(3.3), RoundNearestTiesAway) === T(3) @test round(T(2.5), RoundNearestTiesUp) === round(T(3.3), RoundNearestTiesUp) === T(3) - for Ti in (Integer,Int8,UInt8,Int16,UInt16,Int32,UInt32,Int64,UInt64) + for Ti in (Integer,Int8,UInt8,Int16,UInt16,Int32,UInt32,Int64,UInt64,Int128,UInt128) if Ti != Integer @test parse(T, "17") == T(Ti(17)) == Ti(17) == Ti(T(17)) end From 1628b7083b7a57e35d4ec6d953fa4a2646ac0157 Mon Sep 17 00:00:00 2001 From: John M Kuhn Date: Tue, 19 May 2020 23:29:14 -0400 Subject: [PATCH 2/6] Update Error messages --- src/DecFP.jl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/DecFP.jl b/src/DecFP.jl index 4ce3295..7b84eb5 100644 --- a/src/DecFP.jl +++ b/src/DecFP.jl @@ -498,35 +498,35 @@ for w in (32,64,128) @eval begin function Base.trunc(::Type{$Ti′}, x::$BID) x′ = trunc(x) - (x′ < $BID(typemin($Ti′)) || x′ > $BID(typemax($Ti′))) && throw(InexactError(:convert, $Ti′, x)) + (x′ < typemin($Ti′) || x′ > typemax($Ti′)) && throw(InexactError(:trunc, $Ti′, x)) s, e = sigexp(x′) return flipsign(s * $Ti′(10)^e, x) end function Base.floor(::Type{$Ti′}, x::$BID) x′ = floor(x) - (x′ < $BID(typemin($Ti′)) || x′ > $BID(typemax($Ti′))) && throw(InexactError(:convert, $Ti′, x)) + (x′ < typemin($Ti′) || x′ > typemax($Ti′)) && throw(InexactError(:floor, $Ti′, x)) s, e = sigexp(x′) return flipsign(s * $Ti′(10)^e, x) end function Base.ceil(::Type{$Ti′}, x::$BID) x′ = ceil(x) - (x′ < $BID(typemin($Ti′)) || x′ > $BID(typemax($Ti′))) && throw(InexactError(:convert, $Ti′, x)) + (x′ < typemin($Ti′) || x′ > typemax($Ti′)) && throw(InexactError(:ceil, $Ti′, x)) s, e = sigexp(x′) return flipsign(s * $Ti′(10)^e, x) end function Base.round(::Type{$Ti′}, x::$BID, ::RoundingMode{:NearestTiesAway}) x′ = round(x, RoundNearestTiesAway) - (x′ < $BID(typemin($Ti′)) || x′ > $BID(typemax($Ti′))) && throw(InexactError(:convert, $Ti′, x)) + (x′ < typemin($Ti′) || x′ > typemax($Ti′)) && throw(InexactError(:round, $Ti′, x)) s, e = sigexp(x′) return flipsign(s * $Ti′(10)^e, x) end function Base.convert(::Type{$Ti′}, x::$BID) x != trunc(x) && throw(InexactError(:convert, $Ti′, x)) - (x < $BID(typemin($Ti′)) || x > $BID(typemax($Ti′))) && throw(InexactError(:convert, $Ti′, x)) + (x < typemin($Ti′) || x > typemax($Ti′)) && throw(InexactError(:convert, $Ti′, x)) s, e = sigexp(x) return flipsign(s * $Ti′(10)^e, x) end From ce52277b4be242042a9a13602629a5daddfa7b6c Mon Sep 17 00:00:00 2001 From: John M Kuhn Date: Wed, 20 May 2020 00:10:36 -0400 Subject: [PATCH 3/6] Combine functions --- src/DecFP.jl | 50 ++++++++++++++++++-------------------------------- 1 file changed, 18 insertions(+), 32 deletions(-) diff --git a/src/DecFP.jl b/src/DecFP.jl index 7b84eb5..ab6da52 100644 --- a/src/DecFP.jl +++ b/src/DecFP.jl @@ -495,44 +495,30 @@ for w in (32,64,128) for i′ in (Int128, UInt128) Ti′ = eval(Symbol(i′)) - @eval begin - function Base.trunc(::Type{$Ti′}, x::$BID) - x′ = trunc(x) - (x′ < typemin($Ti′) || x′ > typemax($Ti′)) && throw(InexactError(:trunc, $Ti′, x)) - s, e = sigexp(x′) - return flipsign(s * $Ti′(10)^e, x) - end - - function Base.floor(::Type{$Ti′}, x::$BID) - x′ = floor(x) - (x′ < typemin($Ti′) || x′ > typemax($Ti′)) && throw(InexactError(:floor, $Ti′, x)) - s, e = sigexp(x′) - return flipsign(s * $Ti′(10)^e, x) - end - - function Base.ceil(::Type{$Ti′}, x::$BID) - x′ = ceil(x) - (x′ < typemin($Ti′) || x′ > typemax($Ti′)) && throw(InexactError(:ceil, $Ti′, x)) - s, e = sigexp(x′) - return flipsign(s * $Ti′(10)^e, x) - end - - function Base.round(::Type{$Ti′}, x::$BID, ::RoundingMode{:NearestTiesAway}) - x′ = round(x, RoundNearestTiesAway) - (x′ < typemin($Ti′) || x′ > typemax($Ti′)) && throw(InexactError(:round, $Ti′, x)) + for (f) in (:trunc, :floor, :ceil) + @eval function Base.$f(::Type{$Ti′}, x::$BID) + x′ = $f(x) + (x′ < typemin($Ti′) || x′ > typemax($Ti′)) && throw(InexactError(Symbol($f), $Ti′, x)) s, e = sigexp(x′) return flipsign(s * $Ti′(10)^e, x) end + end - function Base.convert(::Type{$Ti′}, x::$BID) - x != trunc(x) && throw(InexactError(:convert, $Ti′, x)) - (x < typemin($Ti′) || x > typemax($Ti′)) && throw(InexactError(:convert, $Ti′, x)) - s, e = sigexp(x) - return flipsign(s * $Ti′(10)^e, x) - end + @eval function Base.round(::Type{$Ti′}, x::$BID, ::RoundingMode{:NearestTiesAway}) + x′ = round(x, RoundNearestTiesAway) + (x′ < typemin($Ti′) || x′ > typemax($Ti′)) && throw(InexactError(:round, $Ti′, x)) + s, e = sigexp(x′) + return flipsign(s * $Ti′(10)^e, x) + end - Base.$(Symbol("$Ti′"))(x::$BID) = convert($Ti′, x) + @eval function Base.convert(::Type{$Ti′}, x::$BID) + x != trunc(x) && throw(InexactError(:convert, $Ti′, x)) + (x < $BID(typemin($Ti′)) || x > $BID(typemax($Ti′))) && throw(InexactError(:convert, $Ti′, x)) + s, e = sigexp(x) + return flipsign(s * $Ti′(10)^e, x) end + + @eval Base.$(Symbol("$Ti′"))(x::$BID) = convert($Ti′, x) end @eval Base.bswap(x::$BID) = reinterpret($BID, bswap(x.x)) From a504c7ea4700feb951415206154e36cdab8fc4cd Mon Sep 17 00:00:00 2001 From: John M Kuhn Date: Wed, 20 May 2020 12:57:18 -0400 Subject: [PATCH 4/6] Use Integer instead of Int128 where possible --- src/DecFP.jl | 73 ++++++++++++++++++++++------------------------------ 1 file changed, 31 insertions(+), 42 deletions(-) diff --git a/src/DecFP.jl b/src/DecFP.jl index ab6da52..7ec392b 100644 --- a/src/DecFP.jl +++ b/src/DecFP.jl @@ -476,9 +476,6 @@ for w in (32,64,128) end end - @eval Base.convert(::Type{$BID}, x::Int128) = $BID(string(x)) - @eval Base.convert(::Type{$BID}, x::UInt128) = $BID(string(x)) - for w′ in (8,16,32,64) for (i′, i′str) in (("Int$w′", "int$w′"), ("UInt$w′", "uint$w′")) Ti′ = eval(Symbol(i′)) @@ -493,34 +490,6 @@ for w in (32,64,128) end end - for i′ in (Int128, UInt128) - Ti′ = eval(Symbol(i′)) - for (f) in (:trunc, :floor, :ceil) - @eval function Base.$f(::Type{$Ti′}, x::$BID) - x′ = $f(x) - (x′ < typemin($Ti′) || x′ > typemax($Ti′)) && throw(InexactError(Symbol($f), $Ti′, x)) - s, e = sigexp(x′) - return flipsign(s * $Ti′(10)^e, x) - end - end - - @eval function Base.round(::Type{$Ti′}, x::$BID, ::RoundingMode{:NearestTiesAway}) - x′ = round(x, RoundNearestTiesAway) - (x′ < typemin($Ti′) || x′ > typemax($Ti′)) && throw(InexactError(:round, $Ti′, x)) - s, e = sigexp(x′) - return flipsign(s * $Ti′(10)^e, x) - end - - @eval function Base.convert(::Type{$Ti′}, x::$BID) - x != trunc(x) && throw(InexactError(:convert, $Ti′, x)) - (x < $BID(typemin($Ti′)) || x > $BID(typemax($Ti′))) && throw(InexactError(:convert, $Ti′, x)) - s, e = sigexp(x) - return flipsign(s * $Ti′(10)^e, x) - end - - @eval Base.$(Symbol("$Ti′"))(x::$BID) = convert($Ti′, x) - end - @eval Base.bswap(x::$BID) = reinterpret($BID, bswap(x.x)) @eval Base.convert(::Type{Float16}, x::$BID) = convert(Float16, convert(Float32, x)) @eval Base.Float16(x::$BID) = convert(Float16, x) @@ -529,15 +498,36 @@ end # widths w Base.round(x::DecimalFloatingPoint, ::RoundingMode{:FromZero}) = signbit(x) ? floor(x) : ceil(x) -Base.trunc(::Type{Integer}, x::DecimalFloatingPoint) = trunc(Int, x) -Base.floor(::Type{Integer}, x::DecimalFloatingPoint) = floor(Int, x) -Base.ceil(::Type{Integer}, x::DecimalFloatingPoint) = ceil(Int, x) -Base.round(::Type{Integer}, x::DecimalFloatingPoint) = round(Int, x) -Base.round(::Type{Integer}, x::DecimalFloatingPoint, ::RoundingMode{:NearestTiesAway}) = round(Int, x, RoundNearestTiesAway) -Base.convert(::Type{Integer}, x::DecimalFloatingPoint) = convert(Int, x) +for (f) in (:trunc, :floor, :ceil) + @eval function Base.$f(::Type{I}, x::DecimalFloatingPoint) where {I<:Integer} + I′ = I + if I′ == Integer + I′ = Int + end + x′ = $f(x) + typemin(I′) <= x′ <= typemax(I′) || throw(InexactError(Symbol($f), I′, x)) + s, e = sigexp(x′) + return I′(flipsign(s * I′(10)^e, x)) + end +end + +function Base.convert(::Type{I}, x::DecimalFloatingPoint) where {I<:Integer} + I′ = I + if I′ == Integer + I′ = Int + end + x != trunc(x) && throw(InexactError(:convert, I′, x)) + typemin(I′) <= x <= typemax(I′) || throw(InexactError(:convert, I′, x)) + s, e = sigexp(x) + return I′(flipsign(s * I′(10)^e, x)) +end + +Base.Int128(x::DecimalFloatingPoint) = convert(Int128, x) +Base.UInt128(x::DecimalFloatingPoint) = convert(UInt128, x) Base.round(::Type{T}, x::DecimalFloatingPoint) where {T<:Integer} = convert(T, round(x)) Base.round(::Type{T}, x::DecimalFloatingPoint, ::RoundingMode{:Nearest}) where {T<:Integer} = convert(T, round(x, RoundNearest)) +Base.round(::Type{T}, x::DecimalFloatingPoint, ::RoundingMode{:NearestTiesAway}) where {T<:Integer} = convert(T, round(x, RoundNearestTiesAway)) function Base.round(::Type{T}, x::DecimalFloatingPoint, ::RoundingMode{:NearestTiesUp}) where {T<:Integer} y = floor(T, x) ifelse(x==y, y, copysign(floor(T, 2*x-y), x)) @@ -684,11 +674,10 @@ Base.maxintfloat(::Type{Dec32}) = reinterpret(Dec32, 0x36000001) # Dec32("1e7") Base.maxintfloat(::Type{Dec64}) = reinterpret(Dec64, 0x33c0000000000001) # Dec64("1e16") Base.maxintfloat(::Type{Dec128}) = reinterpret(Dec128, 0x30840000000000000000000000000001) # Dec128("1e34") -Base.convert(T::Type{F}, x::Union{Int8,UInt8,Int16,UInt16}) where {F<:DecimalFloatingPoint} = F(Int32(x)) -Base.convert(T::Type{F}, x::Integer) where {F<:DecimalFloatingPoint} = F(Int64(x)) -Base.convert(T::Type{F}, x::Unsigned) where {F<:DecimalFloatingPoint} = F(UInt64(x)) -Base.convert(T::Type{F}, x::Rational) where {F<:DecimalFloatingPoint} = F(x.num) / F(x.den) -Base.convert(T::Type{F}, x::Float16) where {F<:DecimalFloatingPoint} = F(Float32(x)) +Base.convert(::Type{F}, x::Union{Int8,UInt8,Int16,UInt16}) where {F<:DecimalFloatingPoint} = F(Int32(x)) +Base.convert(::Type{F}, x::Integer) where {F<:DecimalFloatingPoint} = F(string(x)) +Base.convert(::Type{F}, x::Rational) where {F<:DecimalFloatingPoint} = F(x.num) / F(x.den) +Base.convert(::Type{F}, x::Float16) where {F<:DecimalFloatingPoint} = F(Float32(x)) promote_rule(::Type{F}, ::Type{Float16}) where {F<:DecimalFloatingPoint} = F promote_rule(::Type{F}, ::Type{T}) where {F<:DecimalFloatingPoint,T<:Union{Int8,UInt8,Int16,UInt16,Int32,UInt32,Int64,UInt64,Int128,UInt128}} = F From 66e014a21479baa2f7a3774af1f6a28916875eab Mon Sep 17 00:00:00 2001 From: John M Kuhn Date: Wed, 20 May 2020 13:32:50 -0400 Subject: [PATCH 5/6] Correctly handle Unsigned conversions --- src/DecFP.jl | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/DecFP.jl b/src/DecFP.jl index 7ec392b..17bb96e 100644 --- a/src/DecFP.jl +++ b/src/DecFP.jl @@ -500,10 +500,7 @@ Base.round(x::DecimalFloatingPoint, ::RoundingMode{:FromZero}) = signbit(x) ? fl for (f) in (:trunc, :floor, :ceil) @eval function Base.$f(::Type{I}, x::DecimalFloatingPoint) where {I<:Integer} - I′ = I - if I′ == Integer - I′ = Int - end + I′ = isabstracttype(I) ? (I <: Unsigned ? UInt : Int) : I x′ = $f(x) typemin(I′) <= x′ <= typemax(I′) || throw(InexactError(Symbol($f), I′, x)) s, e = sigexp(x′) @@ -512,10 +509,7 @@ for (f) in (:trunc, :floor, :ceil) end function Base.convert(::Type{I}, x::DecimalFloatingPoint) where {I<:Integer} - I′ = I - if I′ == Integer - I′ = Int - end + I′ = isabstracttype(I) ? (I <: Unsigned ? UInt : Int) : I x != trunc(x) && throw(InexactError(:convert, I′, x)) typemin(I′) <= x <= typemax(I′) || throw(InexactError(:convert, I′, x)) s, e = sigexp(x) From 659f5574d21d316bf7939c7bfd0bb61843d6fb1f Mon Sep 17 00:00:00 2001 From: John M Kuhn Date: Thu, 21 May 2020 23:18:02 -0400 Subject: [PATCH 6/6] Correct Abstract Integer handling --- src/DecFP.jl | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/DecFP.jl b/src/DecFP.jl index 17bb96e..80226f3 100644 --- a/src/DecFP.jl +++ b/src/DecFP.jl @@ -499,21 +499,27 @@ end # widths w Base.round(x::DecimalFloatingPoint, ::RoundingMode{:FromZero}) = signbit(x) ? floor(x) : ceil(x) for (f) in (:trunc, :floor, :ceil) + @eval Base.$f(::Type{Signed}, x::DecimalFloatingPoint) = $f(Int, x) + @eval Base.$f(::Type{Unsigned}, x::DecimalFloatingPoint) = $f(UInt, x) + @eval Base.$f(::Type{Integer}, x::DecimalFloatingPoint) = $f(Int, x) + @eval function Base.$f(::Type{I}, x::DecimalFloatingPoint) where {I<:Integer} - I′ = isabstracttype(I) ? (I <: Unsigned ? UInt : Int) : I x′ = $f(x) - typemin(I′) <= x′ <= typemax(I′) || throw(InexactError(Symbol($f), I′, x)) + typemin(I) <= x′ <= typemax(I) || throw(InexactError(Symbol($f), I, x)) s, e = sigexp(x′) - return I′(flipsign(s * I′(10)^e, x)) + return I(flipsign(s * I(10)^e, x)) end end +Base.convert(::Type{Signed}, x::DecimalFloatingPoint) = convert(Int, x) +Base.convert(::Type{Unsigned}, x::DecimalFloatingPoint) = convert(UInt, x) +Base.convert(::Type{Integer}, x::DecimalFloatingPoint) = convert(Int, x) + function Base.convert(::Type{I}, x::DecimalFloatingPoint) where {I<:Integer} - I′ = isabstracttype(I) ? (I <: Unsigned ? UInt : Int) : I - x != trunc(x) && throw(InexactError(:convert, I′, x)) - typemin(I′) <= x <= typemax(I′) || throw(InexactError(:convert, I′, x)) + x != trunc(x) && throw(InexactError(:convert, I, x)) + typemin(I) <= x <= typemax(I) || throw(InexactError(:convert, I, x)) s, e = sigexp(x) - return I′(flipsign(s * I′(10)^e, x)) + return I(flipsign(s * I(10)^e, x)) end Base.Int128(x::DecimalFloatingPoint) = convert(Int128, x)