Skip to content

Commit

Permalink
Re-arrange fld/cld code
Browse files Browse the repository at this point in the history
In preparation for supporting other rounding modes in div, create
a three-argument div function that takes a rounding mode as the last
argument and make this the fundamental fallback for fld/cld.
  • Loading branch information
Keno committed Aug 25, 2019
1 parent 96870de commit 9bbf8f5
Show file tree
Hide file tree
Showing 10 changed files with 109 additions and 81 deletions.
1 change: 1 addition & 0 deletions base/Base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ include("namedtuple.jl")
include("hashing.jl")
include("rounding.jl")
using .Rounding
include("div.jl")
include("float.jl")
include("twiceprecision.jl")
include("complex.jl")
Expand Down
2 changes: 0 additions & 2 deletions base/bool.jl
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,5 @@ end
*(y::AbstractFloat, x::Bool) = x * y

div(x::Bool, y::Bool) = y ? x : throw(DivideError())
fld(x::Bool, y::Bool) = div(x,y)
cld(x::Bool, y::Bool) = div(x,y)
rem(x::Bool, y::Bool) = y ? false : throw(DivideError())
mod(x::Bool, y::Bool) = rem(x,y)
74 changes: 74 additions & 0 deletions base/div.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Div is truncating by default
div(a, b) = div(a, b, RoundToZero)

"""
fld(x, y)
Largest integer less than or equal to `x/y`.
# Examples
```jldoctest
julia> fld(7.3,5.5)
1.0
```
"""
fld(a, b) = div(a, b, RoundDown)

"""
cld(x, y)
Smallest integer larger than or equal to `x/y`.
# Examples
```jldoctest
julia> cld(5.5,2.2)
3.0
```
"""
cld(a, b) = div(a, b, RoundUp)

# We definite generic rounding methods for other rounding modes in terms of
# RoundToZero.
div(x::Signed, y::Unsigned, ::typeof(RoundDown)) = div(x, y, RoundToZero) - (signbit(x) & (rem(x, y) != 0))
div(x::Unsigned, y::Signed, ::typeof(RoundDown)) = div(x, y, RoundToZero) - (signbit(y) & (rem(x, y) != 0))

div(x::Signed, y::Unsigned, ::typeof(RoundUp)) = div(x, y, RoundToZero) + (!signbit(x) & (rem(x, y) != 0))
div(x::Unsigned, y::Signed, ::typeof(RoundUp)) = div(x, y, RoundToZero) + (!signbit(y) & (rem(x, y) != 0))

# For bootstrapping purposes, we define div for integers directly. Provide the
# generic signature also
div(a::T, b::T, ::typeof(RoundToZero)) where {T<:Union{BitSigned, BitUnsigned64}} = div(a, b)
div(a::Bool, b::Bool, r::RoundingMode) = div(a, b)

# For compatibility
fld(a::T, b::T) where {T<:Integer} = div(a, b, RoundDown)
cld(a::T, b::T) where {T<:Integer} = div(a, b, RoundDown)

# Promotion
div(x::Real, y::Real, r::RoundingMode) = div(promote(x, y)..., r)

# Integers
# fld(x,y) == div(x,y) - ((x>=0) != (y>=0) && rem(x,y) != 0 ? 1 : 0)
div(x::T, y::T, ::typeof(RoundDown)) where {T<:Unsigned} = div(x,y)
function div(x::T, y::T, ::typeof(RoundDown)) where T<:Integer
d = div(x, y, RoundToZero)
return d - (signbit(x y) & (d * y != x))
end

# cld(x,y) = div(x,y) + ((x>0) == (y>0) && rem(x,y) != 0 ? 1 : 0)
function div(x::T, y::T, ::typeof(RoundUp)) where T<:Unsigned
d = div(x, y, RoundToZero)
return d + (d * y != x)
end
function div(x::T, y::T, ::typeof(RoundUp)) where T<:Integer
d = div(x, y, RoundToZero)
return d + (((x > 0) == (y > 0)) & (d * y != x))
end

# Real
div(x::T, y::T, ::typeof(RoundDown)) where {T<:Real} = convert(T,round((x-mod(x,y))/y))

div(x::T, y::T, ::typeof(RoundUp)) where {T<:Real} = convert(T,round((x-modCeil(x,y))/y))
#rem(x::T, y::T) where {T<:Real} = convert(T,x-y*trunc(x/y))
#mod(x::T, y::T) where {T<:Real} = convert(T,x-y*floor(x/y))
modCeil(x::T, y::T) where {T<:Real} = convert(T,x-y*ceil(x/y))
8 changes: 7 additions & 1 deletion base/gmp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -465,14 +465,20 @@ big(n::Integer) = convert(BigInt, n)

# Binary ops
for (fJ, fC) in ((:+, :add), (:-,:sub), (:*, :mul),
(:fld, :fdiv_q), (:div, :tdiv_q), (:mod, :fdiv_r), (:rem, :tdiv_r),
(:mod, :fdiv_r), (:rem, :tdiv_r),
(:gcd, :gcd), (:lcm, :lcm),
(:&, :and), (:|, :ior), (:xor, :xor))
@eval begin
($fJ)(x::BigInt, y::BigInt) = MPZ.$fC(x, y)
end
end

for (r, f) in ((RoundToZero, :tdiv_q),
(RoundDown, :fdiv_q),
(RoundUp, :cdiv_q))
@eval div(x::BigInt, y::BigInt, ::typeof($r)) = MPZ.$f(x, y)
end

/(x::BigInt, y::BigInt) = float(x)/float(y)

function invmod(x::BigInt, y::BigInt)
Expand Down
25 changes: 0 additions & 25 deletions base/int.jl
Original file line number Diff line number Diff line change
Expand Up @@ -175,10 +175,6 @@ div(x::Unsigned, y::BitSigned) = unsigned(flipsign(signed(div(x, unsigned(abs(y)
rem(x::BitSigned, y::Unsigned) = flipsign(signed(rem(unsigned(abs(x)), y)), x)
rem(x::Unsigned, y::BitSigned) = rem(x, unsigned(abs(y)))

fld(x::Signed, y::Unsigned) = div(x, y) - (signbit(x) & (rem(x, y) != 0))
fld(x::Unsigned, y::Signed) = div(x, y) - (signbit(y) & (rem(x, y) != 0))


"""
mod(x, y)
rem(x, y, RoundDown)
Expand Down Expand Up @@ -220,34 +216,13 @@ mod(x::BitSigned, y::Unsigned) = rem(y + unsigned(rem(x, y)), y)
mod(x::Unsigned, y::Signed) = rem(y + signed(rem(x, y)), y)
mod(x::T, y::T) where {T<:Unsigned} = rem(x, y)

cld(x::Signed, y::Unsigned) = div(x, y) + (!signbit(x) & (rem(x, y) != 0))
cld(x::Unsigned, y::Signed) = div(x, y) + (!signbit(y) & (rem(x, y) != 0))

# Don't promote integers for div/rem/mod since there is no danger of overflow,
# while there is a substantial performance penalty to 64-bit promotion.
div(x::T, y::T) where {T<:BitSigned64} = checked_sdiv_int(x, y)
rem(x::T, y::T) where {T<:BitSigned64} = checked_srem_int(x, y)
div(x::T, y::T) where {T<:BitUnsigned64} = checked_udiv_int(x, y)
rem(x::T, y::T) where {T<:BitUnsigned64} = checked_urem_int(x, y)


# fld(x,y) == div(x,y) - ((x>=0) != (y>=0) && rem(x,y) != 0 ? 1 : 0)
fld(x::T, y::T) where {T<:Unsigned} = div(x,y)
function fld(x::T, y::T) where T<:Integer
d = div(x, y)
return d - (signbit(x y) & (d * y != x))
end

# cld(x,y) = div(x,y) + ((x>0) == (y>0) && rem(x,y) != 0 ? 1 : 0)
function cld(x::T, y::T) where T<:Unsigned
d = div(x, y)
return d + (d * y != x)
end
function cld(x::T, y::T) where T<:Integer
d = div(x, y)
return d + (((x > 0) == (y > 0)) & (d * y != x))
end

## integer bitwise operations ##

"""
Expand Down
6 changes: 5 additions & 1 deletion base/missing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ for f in (:(Base.zero), :(Base.one), :(Base.oneunit))
end

# Binary operators/functions
for f in (:(+), :(-), :(*), :(/), :(^), :(div), :(mod), :(fld), :(rem))
for f in (:(+), :(-), :(*), :(/), :(^), :(mod), :(rem))
@eval begin
# Scalar with missing
($f)(::Missing, ::Missing) = missing
Expand All @@ -117,6 +117,10 @@ for f in (:(+), :(-), :(*), :(/), :(^), :(div), :(mod), :(fld), :(rem))
end
end

div(::Missing, ::Missing, r::RoundingMode) = missing
div(::Missing, ::Number, r::RoundingMode) = missing
div(::Number, ::Missing, r::RoundingMode) = missing

min(::Missing, ::Missing) = missing
min(::Missing, ::Any) = missing
min(::Any, ::Missing) = missing
Expand Down
28 changes: 0 additions & 28 deletions base/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -687,34 +687,6 @@ end
# so it is used here as the basis of float div().
div(x::T, y::T) where {T<:Real} = convert(T,round((x-rem(x,y))/y))

"""
fld(x, y)
Largest integer less than or equal to `x/y`.
# Examples
```jldoctest
julia> fld(7.3,5.5)
1.0
```
"""
fld(x::T, y::T) where {T<:Real} = convert(T,round((x-mod(x,y))/y))

"""
cld(x, y)
Smallest integer larger than or equal to `x/y`.
# Examples
```jldoctest
julia> cld(5.5,2.2)
3.0
```
"""
cld(x::T, y::T) where {T<:Real} = convert(T,round((x-modCeil(x,y))/y))
#rem(x::T, y::T) where {T<:Real} = convert(T,x-y*trunc(x/y))
#mod(x::T, y::T) where {T<:Real} = convert(T,x-y*floor(x/y))
modCeil(x::T, y::T) where {T<:Real} = convert(T,x-y*ceil(x/y))

# operator alias

Expand Down
8 changes: 6 additions & 2 deletions base/promotion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -348,11 +348,15 @@ muladd(x::Number, y::Number, z::Number) = muladd(promote(x,y,z)...)
<=(x::Real, y::Real) = (<=)(promote(x,y)...)

div(x::Real, y::Real) = div(promote(x,y)...)
fld(x::Real, y::Real) = fld(promote(x,y)...)
cld(x::Real, y::Real) = cld(promote(x,y)...)
rem(x::Real, y::Real) = rem(promote(x,y)...)
mod(x::Real, y::Real) = mod(promote(x,y)...)

# These are kept for compatibility with external packages overriding fld/cld.
# In 2.0, packages should extend div(a,b,r) instead, in which case, these can
# be removed.
fld(x::Real, y::Real) = fld(promote(x,y)...)
cld(x::Real, y::Real) = cld(promote(x,y)...)

mod1(x::Real, y::Real) = mod1(promote(x,y)...)
fld1(x::Real, y::Real) = fld1(promote(x,y)...)

Expand Down
28 changes: 12 additions & 16 deletions base/rational.jl
Original file line number Diff line number Diff line change
Expand Up @@ -350,22 +350,18 @@ end
==(z::Complex , x::Rational) = isreal(z) & (real(z) == x)
==(x::Rational, z::Complex ) = isreal(z) & (real(z) == x)

for op in (:div, :fld, :cld)
@eval begin
function ($op)(x::Rational, y::Integer )
xn,yn = divgcd(x.num,y)
($op)(xn, checked_mul(x.den,yn))
end
function ($op)(x::Integer, y::Rational)
xn,yn = divgcd(x,y.num)
($op)(checked_mul(xn,y.den), yn)
end
function ($op)(x::Rational, y::Rational)
xn,yn = divgcd(x.num,y.num)
xd,yd = divgcd(x.den,y.den)
($op)(checked_mul(xn,yd), checked_mul(xd,yn))
end
end
function div(x::Rational, y::Integer, r::RoundingMode)
xn,yn = divgcd(x.num,y)
div(xn, checked_mul(x.den,yn), r)
end
function div(x::Integer, y::Rational, r::RoundingMode)
xn,yn = divgcd(x,y.num)
div(checked_mul(xn,y.den), yn, r)
end
function div(x::Rational, y::Rational, r::RoundingMode)
xn,yn = divgcd(x.num,y.num)
xd,yd = divgcd(x.den,y.den)
div(checked_mul(xn,yd), checked_mul(xd,yn), r)
end

trunc(::Type{T}, x::Rational) where {T} = convert(T,div(x.num,x.den))
Expand Down
10 changes: 4 additions & 6 deletions stdlib/Dates/src/periods.jl
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,10 @@ for op in (:+, :-, :lcm, :gcd)
@eval ($op)(x::P, y::P) where {P<:Period} = P(($op)(value(x), value(y)))
end

for op in (:/, :div, :fld)
@eval begin
($op)(x::P, y::P) where {P<:Period} = ($op)(value(x), value(y))
($op)(x::P, y::Real) where {P<:Period} = P(($op)(value(x), Int64(y)))
end
end
/(x::P, y::P) where {P<:Period} = /(value(x), value(y))
/(x::P, y::Real) where {P<:Period} = P(/(value(x), Int64(y)))
div(x::P, y::P, r::RoundingMode) where {P<:Period} = div(value(x), value(y), r)
div(x::P, y::Real, r::RoundingMode) where {P<:Period} = P(div(value(x), Int64(y), r))

for op in (:rem, :mod)
@eval begin
Expand Down

0 comments on commit 9bbf8f5

Please sign in to comment.