Why is `fld1` not named `cld1`?

question in title; fld1 seems much more similar to cld than fld:

julia> findall(!iszero, [fld1(a,b)-cld(a,b) for a=-10000:.1:10000, b=[-100:-1; 1:100]]) |> length
0

julia> findall(!iszero, [fld1(a,b)-fld(a,b) for a=-10000:.1:10000, b=[-100:-1; 1:100]]) |> length
39792664 

it only seems to match fld when you’re specifically looking for floating pointy weirdness:

julia> fld1(3, 0.3)
10.0

julia> cld(3, 0.3)
11.0

julia> fld(3, 0.3)
10.0

actually, the code for integers appears to be identical, since (0<a) == (0<b) is the same as (a⊻b) >= 0 for non-zero a & b:

julia> @code_typed fld1(20,3)
CodeInfo(
1 ─ %1  = intrinsic Base.checked_sdiv_int(x, y)::Int64
│   %2  = intrinsic Base.xor_int(x, y)::Int64
│   %3  = intrinsic Base.slt_int(%2, 0)::Bool
│   %4  = intrinsic Base.not_int(%3)::Bool
│   %5  = intrinsic Base.mul_int(%1, y)::Int64
│   %6  =   builtin (%5 === x)::Bool
│   %7  = intrinsic Base.not_int(%6)::Bool
│   %8  = intrinsic Base.and_int(%4, %7)::Bool
│   %9  = intrinsic Core.zext_int(Core.Int64, %8)::Int64
│   %10 = intrinsic Core.and_int(%9, 1)::Int64
│   %11 = intrinsic Base.add_int(%1, %10)::Int64
└──       return %11
) => Int64

julia> @code_typed cld(20,3)
CodeInfo(
1 ─ %1  = intrinsic Base.checked_sdiv_int(a, b)::Int64
│   %2  = intrinsic Base.slt_int(0, a)::Bool
│   %3  = intrinsic Base.slt_int(0, b)::Bool
│   %4  =   builtin (%2 === %3)::Bool
│   %5  = intrinsic Base.mul_int(%1, b)::Int64
│   %6  =   builtin (%5 === a)::Bool
│   %7  = intrinsic Base.not_int(%6)::Bool
│   %8  = intrinsic Base.and_int(%4, %7)::Bool
│   %9  = intrinsic Core.zext_int(Core.Int64, %8)::Int64
│   %10 = intrinsic Core.and_int(%9, 1)::Int64
│   %11 = intrinsic Base.add_int(%1, %10)::Int64
└──       return %11
) => Int64

it seems like it would make more sense to call something that’s pretty much cld as cld1, not fld1. is there some theory reason it’s called fld1?

I’ll leave a longer explanation to someone with more time but the short answer is given in its docstring:

  Flooring division, returning a value consistent with mod1(x,y)

but couldn’t that just as easily have been written ceiling division, returning a value consistent with mod1(x,y)? it seems to basically always be the ceiling, not the floor; the doc is just saying that its behavior is defined in terms of mod1 rather than in terms of either cld or fld

And not in the manner that relates fld and mod, as the docstring examples imply:

  julia> x == fld(x, y) * y + mod(x, y)
  true

  julia> x == (fld1(x, y) - 1) * y + mod1(x, y)
  true

which only seems even more similar to cld in many cases.

Relevant, though some behavior has been patched since: fld1: unclear definition and seems broken for non-integers · Issue #14487 · JuliaLang/julia

now I’m even more confused. I had kinda assumed that the equation listed in the docs was its defining property, but that appears to be only true for integer denominators. it seems to be one off about half the time?

julia> [(x-mod1(x, y))/y + 1 - fld1(x,y) for x=-1000:.1:1000, y=[-100:.1:-1.; 1:.1:100]]
20001×1982 Matrix{Float64}:
 0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  …  1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0
 0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0     1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0
 0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0     1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0
 0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0     1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0
 0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0     1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0
 0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  …  1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0
 0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0     1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0
 0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0     1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0
 0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0     1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0
 0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0     1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0
 0.0  1.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  …  1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  0.0  0.0
 0.0  1.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0     1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  0.0  0.0
 0.0  1.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0     1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  0.0  0.0
 0.0  1.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0     1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  0.0  0.0
 0.0  1.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0     1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  0.0  0.0
 0.0  1.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  …  1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  0.0  0.0
 0.0  1.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0     1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  0.0  0.0
 0.0  1.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0     1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  0.0  0.0
 0.0  1.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0     1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  0.0  0.0
 ⋮                        ⋮                        ⋮              ⋱       ⋮                        ⋮                        ⋮
 0.0  0.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0     1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  1.0  0.0
 0.0  0.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0     1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  1.0  0.0
 0.0  0.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0  …  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  1.0  0.0
 0.0  0.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0     1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  1.0  0.0
 0.0  0.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0     1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  1.0  0.0
 0.0  0.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0     1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  1.0  0.0
 0.0  0.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0     1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  1.0  0.0
 0.0  0.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0  …  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  1.0  0.0
 0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0     1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0
 0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0     1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0
 0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0     1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0
 0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0     1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0
 0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0  …  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0
 0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0     1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0
 0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0     1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0
 0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0     1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0
 0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0     1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0
 0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0  0.0  0.0  0.0  1.0  1.0  …  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0  1.0  0.0  1.0  0.0  0.0

funnily enough, it looks like cld does follow the rule:

julia> maximum([(x-mod1(x, y))/y + 1 - cld(x,y) for x=-10000:.1:10000, y=[-100:.1:-.1; .1:.1:100]])
1.4551915228366852e-11

julia> [(x-mod1(x, y))/y + 1 - cld(x,y) for x=-1000:.1:1000, y=[-100:.1:-1.; 1:.1:100]]
20001×1982 Matrix{Float64}:
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  …  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  …  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  …  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  …  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 ⋮                        ⋮                        ⋮              ⋱       ⋮                        ⋮                        ⋮
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  …  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  …  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  …  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  …  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0

maybe it’s a bug, and fld1 should actually just be a deprecated alias for cld?

logically speaking, I guess it would make sense for divrem, fldmod, cldmod1 to all behave similarly

the more I look at this the buggier it seems.

julia> fld1(-0.533669923120631, 3.430469)
-1.0

julia> fld1(prevfloat(-0.533669923120631), 3.430469)
0.0

julia> fld1(nextfloat(-0.533669923120631), 3.430469)
0.0

submitted an issue to github