@floatFromInt doesn't preserve inf

I have to cast to device compatible types and part of that process is reinterpreting f16 to u16. I noticed that inf doesn’t get carried over when using the builtin methods, but pointer casting does:

info: Original: inf
info: Builtin Cast: 3.1744e+04
info: Pointer Cast: inf
pub fn main() !void {

    const x = std.math.inf(f16);

    const u: *const u16 = @ptrCast(&x);

    // @floatFromInt - doesn't preserve inf
    const y: f16 = @floatFromInt(u.*);
    
    // pointer casting - preserves inf
    const z: f16 = @as(*const f16, @ptrCast(u)).*;

    std.log.info("Original: {}", .{ x });
    std.log.info("Builtin Cast: {}", .{ y });
    std.log.info("Pointer Cast: {}", .{ z });
}

Any reason this doesn’t preserve infinity? I’m making custom casting operators to respect original floating point values to handle this, but I’m curious why this is this case.

3 Likes

I opened an issue on Git: floatFromInt builtin doesn't preserve inf · Issue #19280 · ziglang/zig · GitHub

2 Likes

@ianprime0509 pointed out that bit cast will keep the bits intact. I’m suggesting that piece of information should get added to the official docs to prevent accidental lossy conversions :slight_smile:

3 Likes

Yes. @floatFromInt() is actually a conversion.
And since there is no inf for integers, this function just has to do something kinda “logical” with inf. if you look at u.* you’ll see somewhat strange 31744 (0x7C00). But … original inf looks the same, so it seems, for inf that something is just nothing and when actually convert 31744 you got 3.1744e+04, i.e same number (bits in float are 0x77C0).

@ptrCast() as well as @bitCast() is not a conversion, it’s just instructs compiler to reinterpret memory content, which is kept untouched.

2 Likes

Yeah, I had a total brain fart with this yesterday and was mixing categories. I should have caught that but I’ve been busy writing translation code and it totally slipped my mind.