Skip to content

Don't typemin/typemax when unable to #116

New issue

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

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

Already on GitHub? Sign in to your account

Draft
wants to merge 29 commits into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
2e71f3e
Fix ambiguities.
mbarbar Jan 16, 2025
2297c6f
Add tests.
mbarbar Jan 16, 2025
48cc31a
Merge remote-tracking branch 'upstream/master'
mbarbar Jan 16, 2025
c7e0826
Comment
mbarbar Jan 16, 2025
112d5e0
Simplify logic.
mbarbar Jan 16, 2025
68e2935
Merge remote-tracking branch 'upstream/master'
mbarbar Jan 25, 2025
b43473b
Remove promoting with_overflow functions.
mbarbar Jan 25, 2025
48f1d8d
Update tests.
mbarbar Jan 25, 2025
d5ef6e6
Bump to 0.6
mbarbar Jan 28, 2025
5a0dfe5
Update Project.toml
NHDaly Jan 28, 2025
404161e
Merge branch 'master' into master
NHDaly Jan 28, 2025
1399e4f
Add rdiv_with_overflow and fld_with_overflow.
mbarbar Feb 6, 2025
564d841
Add more DIvideError tests.
mbarbar Feb 6, 2025
05381f9
Merge remote-tracking branch 'upstream/master'
mbarbar Feb 6, 2025
3ba8bde
Only on Signed.
mbarbar Feb 6, 2025
a59ebdf
Add signed check
mbarbar Feb 14, 2025
d0cdb98
Remove comment
mbarbar Feb 14, 2025
e45f98e
Merge branch 'master' into master
mbarbar Feb 14, 2025
6976457
Address
mbarbar Feb 15, 2025
ecece4e
Merge remote-tracking branch 'origin/master'
mbarbar Feb 15, 2025
b2f0a82
Apply suggestions from code review
NHDaly Feb 17, 2025
933367b
bump to v0.6.2
NHDaly Feb 17, 2025
f2c33fd
Merge remote-tracking branch 'upstream/master'
mbarbar Feb 18, 2025
bd651eb
Merge remote-tracking branch 'origin/master'
mbarbar Feb 18, 2025
6cc0461
Merge branch 'JuliaMath:master' into master
mbarbar Feb 18, 2025
fc2cbb0
Merge remote-tracking branch 'upstream/master'
mbarbar Feb 21, 2025
ecdd22f
Don't typemin/typemax when unable to.
mbarbar Feb 22, 2025
131cc94
Merge remote-tracking branch 'origin/master'
mbarbar Feb 22, 2025
57d8a89
Comments
mbarbar Feb 22, 2025
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
30 changes: 20 additions & 10 deletions src/FixedPointDecimals.jl
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ import Parsers
# floats that support fma and are roughly IEEE-like
const FMAFloat = Union{Float16, Float32, Float64, BigFloat}

# Is typemin(T) defined?
_has_typemin(::Type{T}) where T = hasmethod(typemin, (Type{T},))
# Is typemax(T) defined?
_has_typemax(::Type{T}) where T = hasmethod(typemax, (Type{T},))
# Can v be represented by T?
function _fits(v::Integer, ::Type{T}) where T <: Integer
limitless = !(_has_typemax(T) && _has_typemin(T))
return limitless || typemin(T) <= v <= typemax(T)
end

for fn in [:trunc, :floor, :ceil]
fnname = Symbol(fn, "mul")
fnname_str = String(fnname)
Expand Down Expand Up @@ -324,7 +334,7 @@ Base.convert(::Type{FD{T, f}}, x::FD{T, f}) where {T, f} = x # Converting an FD
function Base.convert(::Type{FD{T, f}}, x::Integer) where {T, f}
C = coefficient(FD{T, f})
throw_inexact() = throw(InexactError(:convert, FD{T, f}, x))
typemin(T) <= x <= typemax(T) || throw_inexact()
_fits(x, T) || throw_inexact()
xT = convert(T, x) # This won't throw, since we already checked, above.
# Perform x * C, and check for overflow. This is cheaper than a widemul, especially for
# 128-bit T, since those widen into a BigInt.
Expand Down Expand Up @@ -427,7 +437,7 @@ function Base.Checked.mul_with_overflow(x::FD{T,f}, y::FD{T,f}) where {T<:Intege
powt = coefficient(FD{T, f})
quotient, remainder = fldmodinline(_widemul(x.i, y.i), powt)
v = _round_to_nearest(quotient, remainder, powt)
return (reinterpret(FD{T,f}, rem(v, T)), v < typemin(T) || v > typemax(T))
return (reinterpret(FD{T,f}, rem(v, T)), !_fits(v, T))
end

# This does not exist in Base so is just part of this package.
Expand All @@ -442,7 +452,7 @@ overflow/underflow did in fact happen. Throws a DivideError on divide-by-zero.
function div_with_overflow(x::FD{T,f}, y::FD{T,f}) where {T<:Integer,f}
C = coefficient(FD{T, f})
# This case will break the div call below.
if y.i == -1 && T <: Signed && hasmethod(typemin, (Type{T},)) && x.i == typemin(T)
if y.i == -1 && T <: Signed && _has_typemin(T) && x.i == typemin(T)
# To perform the div and overflow means reaching the max and adding 1, so typemin.
return (x, true)
end
Expand All @@ -467,7 +477,7 @@ See also:
function fld_with_overflow(x::FD{T,f}, y::FD{T,f}) where {T<:Integer,f}
C = coefficient(FD{T, f})
# This case will break the fld call below.
if y.i == -1 && T <: Signed && hasmethod(typemin, (Type{T},)) && x.i == typemin(T)
if y.i == -1 && T <: Signed && _has_typemin(T) && x.i == typemin(T)
# To fld and overflow means reaching the max and adding 1, so typemin (x).
return (x, true)
end
Expand All @@ -494,7 +504,7 @@ function rdiv_with_overflow(x::FD{T,f}, y::FD{T,f}) where {T<:Integer,f}
# quotient is necessarily not typemax/typemin. x.i * powt cannot reach typemax/typemin
# of the widened type and y.i is an integer. Thus the following call cannot overflow.
v = _round_to_nearest(quotient, remainder, y.i)
return (reinterpret(FD{T,f}, rem(v, T)), v < typemin(T) || v > typemax(T))
return (reinterpret(FD{T,f}, rem(v, T)), !_fits(v, T))
end

# These functions allow us to perform division with integers outside of the range of the
Expand All @@ -510,7 +520,7 @@ function rdiv_with_overflow(x::Integer, y::FD{T, f}) where {T<:Integer, f}
return (reinterpret(FD{T,f}, rem(v, T)), v < typemin(T) || v > typemax(T))
end
function rdiv_with_overflow(x::FD{T, f}, y::Integer) where {T<:Integer, f}
if y == -1 && T <: Signed && hasmethod(typemin, (Type{T},)) && x.i == typemin(T)
if y == -1 && T <: Signed && _has_typemin(T) && x.i == typemin(T)
# typemin / -1 for signed integers wraps, giving typemin (x) again.
return (x, true)
end
Expand Down Expand Up @@ -806,11 +816,11 @@ for comp_op in (:(==), :(<), :(<=))
return $comp_op(x, y.i)
else
if !(x isa T)
if x > typemax(T)
if _has_typemax(T) && x > typemax(T)
# If x is too big to fit in T, then we know already that it's bigger
# than y, so not equal and not less than.
return false
elseif x < typemin(T)
elseif _has_typemin(T) && x < typemin(T)
# Similarly, if too small, it's definitely less than y (and not equal).
return $(comp_op == :(==)) ? false : true
end
Expand Down Expand Up @@ -840,11 +850,11 @@ for comp_op in (:(==), :(<), :(<=))
return $comp_op(x.i, y)
else
if !(y isa T)
if y > typemax(T)
if _has_typemax(T) && y > typemax(T)
# If y is too big to fit in T, then we know already that x is smaller
# than y. So not equal, but definitely x < y.
return $(comp_op == :(==)) ? false : true
elseif y < typemin(T)
elseif _has_typemin(T) && y < typemin(T)
# Similarly, if y is too small, definitely x > y (and not equal).
return false
end
Expand Down
Loading