Skip to content

Commit

Permalink
Merge pull request #8111 from eschnett/cld
Browse files Browse the repository at this point in the history
Implement cld
  • Loading branch information
JeffBezanson committed Sep 7, 2014
2 parents f20ddba + f2d7b9a commit f665dae
Show file tree
Hide file tree
Showing 12 changed files with 152 additions and 5 deletions.
1 change: 1 addition & 0 deletions base/bool.jl
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,6 @@ end

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)
1 change: 1 addition & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ export
ceil,
cis,
clamp,
cld,
cmp,
combinations,
complex,
Expand Down
2 changes: 2 additions & 0 deletions base/float.jl
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ widen(::Type{Float32}) = Float64
rem(x::Float32, y::Float32) = box(Float32,rem_float(unbox(Float32,x),unbox(Float32,y)))
rem(x::Float64, y::Float64) = box(Float64,rem_float(unbox(Float64,x),unbox(Float64,y)))

cld{T<:FloatingPoint}(x::T, y::T) = -fld(-x,y)

mod{T<:FloatingPoint}(x::T, y::T) = rem(y+rem(x,y),y)

## floating point comparisons ##
Expand Down
6 changes: 6 additions & 0 deletions base/int.jl
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ fld(x::Unsigned, y::Signed) = div(x,y)-(signbit(y)&(rem(x,y)!=0))
mod(x::Signed, y::Unsigned) = rem(y+unsigned(rem(x,y)),y)
mod(x::Unsigned, y::Signed) = rem(y+signed(rem(x,y)),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 no danger of overflow,
# while there is a substantial performance penalty to 64-bit promotion.
typealias Signed64 Union(Int8,Int16,Int32,Int64)
Expand All @@ -105,6 +108,9 @@ mod{T<:Unsigned}(x::T, y::T) = rem(x,y)
fld{T<:Unsigned}(x::T, y::T) = div(x,y)
fld{T<:Integer }(x::T, y::T) = div(x,y)-(signbit(x$y)&(rem(x,y)!=0))

cld{T<:Unsigned}(x::T, y::T) = div(x,y)+(rem(x,y)!=0)
cld{T<:Integer }(x::T, y::T) = div(x,y)+(!signbit(x$y)&(rem(x,y)!=0))

## integer bitwise operations ##

~(x::Int8 ) = box(Int8,not_int(unbox(Int8,x)))
Expand Down
4 changes: 3 additions & 1 deletion base/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -112,13 +112,15 @@ const .≠ = .!=
>>(x,y::Integer) = x >> convert(Int32,y)
>>>(x,y::Integer) = x >>> convert(Int32,y)

# fallback div and fld implementations
# fallback div, fld, and cld implementations
# NOTE: C89 fmod() and x87 FPREM implicitly provide truncating float division,
# so it is used here as the basis of float div().
div{T<:Real}(x::T, y::T) = convert(T,round((x-rem(x,y))/y))
fld{T<:Real}(x::T, y::T) = convert(T,round((x-mod(x,y))/y))
cld{T<:Real}(x::T, y::T) = convert(T,round((x-modCeil(x,y))/y))
#rem{T<:Real}(x::T, y::T) = convert(T,x-y*trunc(x/y))
#mod{T<:Real}(x::T, y::T) = convert(T,x-y*floor(x/y))
modCeil{T<:Real}(x::T, y::T) = convert(T,x-y*ceil(x/y))

# operator alias
const % = rem
Expand Down
1 change: 1 addition & 0 deletions base/promotion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ promote_to_super{T<:Number,S<:Number}(::Type{T}, ::Type{S}, ::Type) =

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)...)

Expand Down
6 changes: 5 additions & 1 deletion base/rational.jl
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,13 @@ fld(x::Rational, y::Rational) = fld(x.num*y.den, x.den*y.num)
fld(x::Rational, y::Real ) = fld(x.num, x.den*y)
fld(x::Real , y::Rational) = fld(x*y.den, y.num)

cld(x::Rational, y::Rational) = cld(x.num*y.den, x.den*y.num)
cld(x::Rational, y::Real ) = cld(x.num, x.den*y)
cld(x::Real , y::Rational) = cld(x*y.den, y.num)

itrunc(x::Rational) = div(x.num,x.den)
ifloor(x::Rational) = fld(x.num,x.den)
iceil (x::Rational) = -fld(-x.num,x.den)
iceil (x::Rational) = cld(x.num,x.den)
iround(x::Rational) = div(x.num*2 + copysign(x.den,x.num), x.den*2)

trunc(x::Rational) = Rational(itrunc(x))
Expand Down
6 changes: 6 additions & 0 deletions doc/helpdb.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3552,6 +3552,12 @@ popdisplay(d::Display)
"),

("Base","cld","cld(a, b)
Smallest integer larger than or equal to a/b.
"),

("Base","mod","mod(x, m)
Modulus after division, returning in the range [0,m).
Expand Down
1 change: 1 addition & 0 deletions doc/manual/mathematical-operations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ Function Description
=============== =======================================================================
``div(x,y)`` truncated division; quotient rounded towards zero
``fld(x,y)`` floored division; quotient rounded towards ``-Inf``
``cld(x,y)`` ceiling division; quotient rounded towards ``+Inf``
``rem(x,y)`` remainder; satisfies ``x == div(x,y)*y + rem(x,y)``; sign matches ``x``
``divrem(x,y)`` returns ``(div(x,y),rem(x,y))``
``mod(x,y)`` modulus; satisfies ``x == fld(x,y)*y + mod(x,y)``; sign matches ``y``
Expand Down
3 changes: 2 additions & 1 deletion doc/manual/performance-tips.rst
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,8 @@ These are some minor points that might help in tight inner loops.
- Use ``abs2(z)`` instead of ``abs(z)^2`` for complex ``z``. In general,
try to rewrite code to use ``abs2`` instead of ``abs`` for complex arguments.
- Use ``div(x,y)`` for truncating division of integers instead of
``trunc(x/y)``, and ``fld(x,y)`` instead of ``floor(x/y)``.
``trunc(x/y)``, ``fld(x,y)`` instead of ``floor(x/y)``, and
``cld(x,y)`` instead of ``ceil(x/y)``.

Performance Annotations
-----------------------
Expand Down
4 changes: 4 additions & 0 deletions doc/stdlib/base.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2515,6 +2515,10 @@ Mathematical Operators

Largest integer less than or equal to a/b.

.. function:: cld(a,b)

Smallest integer larger than or equal to a/b.

.. function:: mod(x,m)

Modulus after division, returning in the range [0,m).
Expand Down
122 changes: 120 additions & 2 deletions test/numbers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -843,7 +843,7 @@ end
@test_throws MethodError complex(1,2) > 0
@test_throws MethodError complex(1,2) > complex(0,0)

# div, fld, rem, mod
# div, fld, cld, rem, mod
for yr = {
1:6,
0.25:0.25:6.0,
Expand Down Expand Up @@ -912,9 +912,48 @@ for yr = {
@test fld(-x,-y) == +2
end

# check everything else in terms of div & fld
# check basic cld functionality
if 0 == x
@test cld(+x,+y) == 0
@test cld(+x,-y) == 0
@test cld(-x,+y) == 0
@test cld(-x,-y) == 0
end
if 0 < x < 1y
@test cld(+x,+y) == +1
@test cld(+x,-y) == +0
@test cld(-x,+y) == +0
@test cld(-x,-y) == +1
end
if 1y == x
@test cld(+x,+y) == +1
@test cld(+x,-y) == -1
@test cld(-x,+y) == -1
@test cld(-x,-y) == +1
end
if 1y < x < 2y
@test cld(+x,+y) == +2
@test cld(+x,-y) == -1
@test cld(-x,+y) == -1
@test cld(-x,-y) == +2
end
if 2y == x
@test cld(+x,+y) == +2
@test cld(+x,-y) == -2
@test cld(-x,+y) == -2
@test cld(-x,-y) == +2
end
if 2y < x < 3y
@test cld(+x,+y) == +3
@test cld(+x,-y) == -2
@test cld(-x,+y) == -2
@test cld(-x,-y) == +3
end

# check everything else in terms of div, fld, cld
d = div(x,y)
f = fld(x,y)
c = cld(x,y)
r = rem(x,y)
m = mod(x,y)

Expand All @@ -928,10 +967,12 @@ for yr = {

@test typeof(d) <: t1
@test typeof(f) <: t1
@test typeof(c) <: t1
@test typeof(r) <: t2
@test typeof(m) <: t2

@test d == f
@test c == f + (m == 0 ? 0 : 1)
@test r == m
@test 0 <= r < y
@test x == y*d + r
Expand All @@ -942,11 +983,13 @@ for yr = {

sd = div(sx,sy)
sf = fld(sx,sy)
sc = cld(sx,sy)
sr = rem(sx,sy)
sm = mod(sx,sy)

@test typeof(sd) <: t1
@test typeof(sf) <: t1
@test typeof(sc) <: t1
@test typeof(sr) <: t2
@test typeof(sm) <: t2

Expand Down Expand Up @@ -1046,17 +1089,63 @@ end
@test fld(typemin(Int64)+3,-2) == 4611686018427387902
@test fld(typemin(Int64)+3,-7) == 1317624576693539400

@test cld(typemax(Int64) , 1) == 9223372036854775807
@test cld(typemax(Int64) , 2) == 4611686018427387904
@test cld(typemax(Int64) , 7) == 1317624576693539401
@test cld(typemax(Int64) ,-1) == -9223372036854775807
@test cld(typemax(Int64) ,-2) == -4611686018427387903
@test cld(typemax(Int64) ,-7) == -1317624576693539401
@test cld(typemax(Int64)-1, 1) == 9223372036854775806
@test cld(typemax(Int64)-1, 2) == 4611686018427387903
@test cld(typemax(Int64)-1, 7) == 1317624576693539401
@test cld(typemax(Int64)-1,-1) == -9223372036854775806
@test cld(typemax(Int64)-1,-2) == -4611686018427387903
@test cld(typemax(Int64)-1,-7) == -1317624576693539400
@test cld(typemax(Int64)-2, 1) == 9223372036854775805
@test cld(typemax(Int64)-2, 2) == 4611686018427387903
@test cld(typemax(Int64)-2, 7) == 1317624576693539401
@test cld(typemax(Int64)-2,-1) == -9223372036854775805
@test cld(typemax(Int64)-2,-2) == -4611686018427387902
@test cld(typemax(Int64)-2,-7) == -1317624576693539400

@test cld(typemin(Int64) , 1) == -9223372036854775807-1
@test cld(typemin(Int64) , 2) == -4611686018427387904
@test cld(typemin(Int64) , 7) == -1317624576693539401
#@test cld(typemin(Int64) ,-1) == -9223372036854775807-1 # FIXME!
@test cld(typemin(Int64) ,-2) == 4611686018427387904
@test cld(typemin(Int64) ,-7) == 1317624576693539402
@test cld(typemin(Int64)+1, 1) == -9223372036854775807
@test cld(typemin(Int64)+1, 2) == -4611686018427387903
@test cld(typemin(Int64)+1, 7) == -1317624576693539401
@test cld(typemin(Int64)+1,-1) == 9223372036854775807
@test cld(typemin(Int64)+1,-2) == 4611686018427387904
@test cld(typemin(Int64)+1,-7) == 1317624576693539401
@test cld(typemin(Int64)+2, 1) == -9223372036854775806
@test cld(typemin(Int64)+2, 2) == -4611686018427387903
@test cld(typemin(Int64)+2, 7) == -1317624576693539400
@test cld(typemin(Int64)+2,-1) == 9223372036854775806
@test cld(typemin(Int64)+2,-2) == 4611686018427387903
@test cld(typemin(Int64)+2,-7) == 1317624576693539401
@test cld(typemin(Int64)+3, 1) == -9223372036854775805
@test cld(typemin(Int64)+3, 2) == -4611686018427387902
@test cld(typemin(Int64)+3, 7) == -1317624576693539400
@test cld(typemin(Int64)+3,-1) == 9223372036854775805
@test cld(typemin(Int64)+3,-2) == 4611686018427387903
@test cld(typemin(Int64)+3,-7) == 1317624576693539401

for x={typemin(Int64), -typemax(Int64), -typemax(Int64)+1, -typemax(Int64)+2,
typemax(Int64)-2, typemax(Int64)-1, typemax(Int64),
typemax(Uint64)-1, typemax(Uint64)-2, typemax(Uint64)},
y={-7,-2,-1,1,2,7}
if x >= 0
@test div(unsigned(x),y) == unsigned(div(x,y))
@test fld(unsigned(x),y) == unsigned(fld(x,y))
@test cld(unsigned(x),y) == unsigned(cld(x,y))
end
if isa(x,Signed) && y >= 0
@test div(x,unsigned(y)) == div(x,y)
@test fld(x,unsigned(y)) == fld(x,y)
@test cld(x,unsigned(y)) == cld(x,y)
end
end

Expand All @@ -1073,6 +1162,12 @@ for x=0:5, y=1:5
@test fld(uint(x),-y) == uint(fld(x,-y))
@test fld(-x,uint(y)) == fld(-x,y)

@test cld(uint(x),uint(y)) == cld(x,y)
@test cld(uint(x),y) == cld(x,y)
@test cld(x,uint(y)) == cld(x,y)
@test cld(uint(x),-y) == uint(cld(x,-y))
@test cld(-x,uint(y)) == cld(-x,y)

@test rem(uint(x),uint(y)) == rem(x,y)
@test rem(uint(x),y) == rem(x,y)
@test rem(x,uint(y)) == rem(x,y)
Expand Down Expand Up @@ -1130,6 +1225,28 @@ end
@test signed(fld(typemax(Uint),typemin(Int)>>1)) == -4
@test signed(fld(typemax(Uint),(typemin(Int)>>1)+1)) == -5

@test cld(typemax(Uint64) , 1) == typemax(Uint64)
@test cld(typemax(Uint64) ,-1) == -typemax(Uint64)
@test cld(typemax(Uint64)-1, 1) == typemax(Uint64)-1
@test cld(typemax(Uint64)-1,-1) == -typemax(Uint64)+1
@test cld(typemax(Uint64)-2, 1) == typemax(Uint64)-2
@test cld(typemax(Uint64)-2,-1) == -typemax(Uint64)+2

@test signed(cld(unsigned(typemax(Int64))+2, 1)) == typemax(Int64)+2
@test signed(cld(unsigned(typemax(Int64))+2,-1)) == -typemax(Int64)-2
@test signed(cld(unsigned(typemax(Int64))+1, 1)) == typemax(Int64)+1
@test signed(cld(unsigned(typemax(Int64))+1,-1)) == -typemax(Int64)-1
@test signed(cld(unsigned(typemax(Int64)) , 1)) == typemax(Int64)
@test signed(cld(unsigned(typemax(Int64)) ,-1)) == -typemax(Int64)

@test signed(cld(typemax(Uint),typemax(Int))) == 3
@test signed(cld(typemax(Uint),(typemax(Int)>>1)+1)) == 4
@test signed(cld(typemax(Uint),typemax(Int)>>1)) == 5
@test signed(cld(typemax(Uint),typemin(Int))) == -1
@test signed(cld(typemax(Uint),typemin(Int)+1)) == -2
@test signed(cld(typemax(Uint),typemin(Int)>>1)) == -3
@test signed(cld(typemax(Uint),(typemin(Int)>>1)+1)) == -4

# issue #4156
@test fld(1.4,0.35667494393873234) == 3.0
@test div(1.4,0.35667494393873234) == 3.0
Expand Down Expand Up @@ -1165,6 +1282,7 @@ end

@test div(1e50,1) == 1e50
@test fld(1e50,1) == 1e50
@test cld(1e50,1) == 1e50

# rounding difficult values

Expand Down

0 comments on commit f665dae

Please sign in to comment.