Skip to content

Commit f44b19e

Browse files
authored
Merge pull request #118 from JuliaMath/aa/rem-round
Implement `rem` with rounding modes and make `RoundToZero` the default mode
2 parents ce4ae63 + 08326eb commit f44b19e

2 files changed

Lines changed: 69 additions & 1 deletion

File tree

‎src/Quadmath.jl‎

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,8 +346,26 @@ end
346346
Float128(@quad_ccall(@autoql(atan2)(x::Cfloat128, y::Cfloat128)::Cfloat128))
347347

348348
Base.Integer(x::Float128) = Int(x)
349-
@assume_effects :foldable Base.rem(x::Float128, y::Float128) =
349+
@assume_effects :foldable Base.rem(x::Float128, y::Float128, ::RoundingMode{:Nearest}) =
350350
Float128(@quad_ccall(@autoql(remainder)(x::Cfloat128, y::Cfloat128)::Cfloat128))
351+
@assume_effects :foldable Base.rem(x::Float128, y::Float128, ::RoundingMode{:ToZero}=RoundToZero) =
352+
Float128(@quad_ccall(@autoql(fmod)(x::Cfloat128, y::Cfloat128)::Cfloat128))
353+
354+
if VERSION < v"1.14.0-DEV.2070"
355+
# This method was copied from Julia commit 117a6c50f5e, which added a generic method.
356+
# License is MIT: https://julialang.org/license.
357+
function Base.rem(x::Float128, y::Float128, rnd::Union{typeof(RoundNearestTiesAway),
358+
typeof(RoundNearestTiesUp)})
359+
r = mod(x, y)
360+
isnan(r) && return r
361+
if !iszero(r)
362+
m, n = abs(r) < floatmax(r)/2 ? abs.((2r, y)) : abs.((r, y/2))
363+
m < n && return r
364+
m > n && return mod(x, -y)
365+
end
366+
rnd === RoundNearestTiesUp || signbit(x) == signbit(y) ? mod(x, -y) : r
367+
end
368+
end
351369

352370
sincos(x::Float128) = (sin(x), cos(x))
353371

‎test/rounding.jl‎

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,3 +308,53 @@ end
308308
end
309309
end
310310
end
311+
312+
# These tests were copied from Julia. License is MIT: https://julialang.org/license.
313+
@testset "rounding consistency with Base" begin
314+
@test rem(prevfloat(Float128(1)), Float128(1)) == prevfloat(Float128(1))
315+
@test mod(prevfloat(Float128(1)), Float128(1)) == prevfloat(Float128(1))
316+
end
317+
@testset "rem(::Float128, ::Float128, ::RoundingMode)" begin
318+
T = Float128
319+
@test rem(T(1), T(2), RoundToZero) == 1
320+
@test rem(T(1), T(2), RoundNearest) == 1
321+
@test rem(T(1), T(2), RoundDown) == 1
322+
@test rem(T(1), T(2), RoundUp) == -1
323+
@test rem(T(1), T(2), RoundFromZero) == -1
324+
@test rem(T(1), T(2), RoundNearestTiesUp) == -1
325+
@test rem(T(1), T(2), RoundNearestTiesAway) == -1
326+
@test rem(T(1.5), T(2), RoundToZero) == 1.5
327+
@test rem(T(1.5), T(2), RoundNearest) == -0.5
328+
@test rem(T(1.5), T(2), RoundDown) == 1.5
329+
@test rem(T(1.5), T(2), RoundUp) == -0.5
330+
@test rem(T(1.5), T(2), RoundFromZero) == -0.5
331+
@test rem(T(1.5), T(2), RoundNearestTiesUp) == -0.5
332+
@test rem(T(1.5), T(2), RoundNearestTiesAway) == -0.5
333+
@test rem(T(-1), T(2), RoundToZero) == -1
334+
@test rem(T(-1), T(2), RoundNearest) == -1
335+
@test rem(T(-1), T(2), RoundDown) == 1
336+
@test rem(T(-1), T(2), RoundUp) == -1
337+
@test rem(T(-1), T(2), RoundFromZero) == 1
338+
@test rem(T(-1), T(2), RoundNearestTiesUp) == -1
339+
@test rem(T(-1), T(2), RoundNearestTiesAway) == 1
340+
@test rem(T(-1.5), T(2), RoundToZero) == -1.5
341+
@test rem(T(-1.5), T(2), RoundNearest) == 0.5
342+
@test rem(T(-1.5), T(2), RoundDown) == 0.5
343+
@test rem(T(-1.5), T(2), RoundUp) == -1.5
344+
@test rem(T(-1.5), T(2), RoundFromZero) == 0.5
345+
@test rem(T(-1.5), T(2), RoundNearestTiesUp) == 0.5
346+
@test rem(T(-1.5), T(2), RoundNearestTiesAway) == 0.5
347+
for mode in [RoundToZero, RoundNearest, RoundDown, RoundUp, RoundFromZero, RoundNearestTiesUp, RoundNearestTiesAway]
348+
@test isnan(rem(T(1), T(0), mode))
349+
@test isnan(rem(T(Inf), T(2), mode))
350+
@test isnan(rem(T(1), T(NaN), mode))
351+
@test rem(T(4), floatmin(T) * 2, mode) == 0
352+
end
353+
@test isequal(rem(nextfloat(typemin(T)), T(2), RoundToZero), -0.0)
354+
@test isequal(rem(nextfloat(typemin(T)), T(2), RoundNearest), -0.0)
355+
@test isequal(rem(nextfloat(typemin(T)), T(2), RoundDown), 0.0)
356+
@test isequal(rem(nextfloat(typemin(T)), T(2), RoundUp), -0.0)
357+
@test isequal(rem(nextfloat(typemin(T)), T(2), RoundFromZero), 0.0)
358+
@test isequal(rem(nextfloat(typemin(T)), T(2), RoundNearestTiesUp), -0.0)
359+
@test isequal(rem(nextfloat(typemin(T)), T(2), RoundNearestTiesAway), 0.0)
360+
end

0 commit comments

Comments
 (0)