Skip to content

Specialization of Normed{UInt16} -> Float32 conversions #373

Closed

Description

@kimikage

While working on the PR #372 benchmarks, I realized that some Normed{Uint16}->Float32 conversions hadn't been optimized (or specialized). (cf. Issue #129, PR #138)

function Base.Float32(x::Normed{UInt16,f}) where f
f32 = Float32(x.i)
f == 1 && return f32
f == 2 && return f32 * @f32(0x55p-8) + f32 * @f32(0x555555p-32)
f == 3 && return f32 * @f32(0x49p-9) + f32 * @f32(0x249249p-33)
f == 4 && return f32 * @f32(0x11p-8) + f32 * @f32(0x111111p-32)
f == 5 && return f32 * @f32(0x21p-10) + f32 * @f32(0x108421p-35)
f == 6 && return f32 * @f32(0x41p-12) + f32 * @f32(0x041041p-36)
f == 7 && return f32 * @f32(0x81p-14) + f32 * @f32(0x204081p-42)
f == 16 && return f32 * @f32(0x01p-16) + f32 * @f32(0x010001p-48)
Float32(x.i / rawone(x))
end

Compared to seven years ago, Julia has become more flexible in terms of broadcasting and inlining.
Furthermore, even taking into account the previous constraints in Julia, the following should still be effective.

    f == 10 && return Float32(Int32(x.i) * 0xcd) * @f32(0x500005p-40)

Also, I think the f==8 case, which is used relatively often, is worth optimizing.

    if f == 8
        s = x.i <= 0xff00
        f32m = Float32(x.i - (s ? 0x0000 : 0xff00))
        return f32m * @f32(0x101p-16) + f32m * @f32(0x1p-24) + (s ? 0f0 : 256f0)
    end

Although the handling of fma() has improved compared to seven years ago, the performance penalty in the absence of hardware support is still significant, so we should avoid using it to improve speed rather than accuracy.

It might be okay to use Float64 operations, but I don't have a thorough understanding of GPU compatibility or performance with Float64.

Activity

  1. kimikage commented on Oct 31, 2026

    @kimikage
    CollaboratorAuthor

    After attempting to optimize the N4f12 and N2f14 cases, I would like to submit a PR (even if that means giving up for the two cases).

  2. kimikage commented on Oct 31, 2026

    @kimikage
    CollaboratorAuthor

    Was I overcomplicating things?🤔

    function f32a(x::Normed{UInt16,f}) where f
        f32 = Float32(x.i)
        y0 = f32 * Float32(FixedPointNumbers.inv_rawone(x))
        r = y0 - (y0 * Float32(2^f) - f32)
        y0 + r * Float32(FixedPointNumbers.inv_rawone(x))
    end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions