Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement proper f128 float printing #1181

Closed
tiehuis opened this issue Jun 30, 2018 · 5 comments · Fixed by #19229
Closed

Implement proper f128 float printing #1181

tiehuis opened this issue Jun 30, 2018 · 5 comments · Fixed by #19229
Labels
enhancement Solving this issue will likely involve adding new logic or components to the codebase. standard library This issue involves writing Zig code for the standard library.
Milestone

Comments

@tiehuis
Copy link
Member

tiehuis commented Jun 30, 2018

Right now we cast f128 to a f64 and simply lose any excess precision we otherwise had. This may be fairly involved as errol3 (the current float printing algorithm used) is specified using f64 digits only. Will have to check the algorithm and see the appropriate modifications needed for the wider range.

@tiehuis tiehuis added the enhancement Solving this issue will likely involve adding new logic or components to the codebase. label Jun 30, 2018
@tiehuis tiehuis added this to the 1.0.0 milestone Jun 30, 2018
@andrewrk andrewrk added the standard library This issue involves writing Zig code for the standard library. label Mar 21, 2019
@shawnl
Copy link
Contributor

shawnl commented Mar 23, 2019

negative zero is also printed as positive zero:


    var negative_zero: f32 = -0.0;
    std.debug.warn("\n{}\n", negative_zero);

0.0e+00

@andrewrk
Copy link
Member

I would like to propose that the default float printing and default float parsing in Zig should have roundtrip bit-for-bit value preservation for all values for all float types.

So that means that this fuzz test should never fail:

const std = @import("std");

test "fuzz test float printing and parsing" {
    const seed = 0x1234;
    var prng = std.rand.DefaultPrng.init(seed);
    var buf: [1024]u8 = undefined; // i don't know how big this should be
    while (true) {
        inline for ([]type{ f16, f32, f64, f128 }) |F| {
            const I = @IntType(false, F.bit_count);
            const rand_int = prng.random.int(I);
            const rand_float = @bitCast(F, rand_int);
            const serialized = std.fmt.bufPrint(&buf, "{}", rand_float) catch unreachable;
            const deserialized = std.fmt.parseFloat(F, serialized) catch unreachable;
            std.testing.expect(rand_int == @bitCast(I, deserialized));
        }
    }
}

Right now this test is a bug report generator :-)

Maybe an exception should be made for negative NaN? I'm not sure exactly what the rules are about that particular case right now.

@shawnl
Copy link
Contributor

shawnl commented Mar 24, 2019

Maybe an exception should be made for negative NaN?

There are more than 2 representations of NaN, and ALL must be normalized to a single representation.

@LewisGaul
Copy link
Contributor

Just a note (perhaps stating the obvious) - it's not just the extra precision of f128 that's lost when casting to f64, it's also the range. E.g. anything above 0x1p1024 is displayed as inf, even though f128 allows up to 0x1p16384 (and similar for negative numbers).

@matteo-briani
Copy link
Contributor

I was studying the issue, but I had to change the bug-report-generator code to comply with latest zig compiler (at the time of writing 0.12.0-dev.1396+f6de3ec96).
Hoping it could be of some help, I post here the updated code.

const std = @import("std");

test "fuzz test float printing and parsing" {
    const seed = 0x1234;
    var prng = std.rand.DefaultPrng.init(seed);
    var buf: [1024]u8 = undefined; // i don't know how big this should be
    while (true) {
        inline for ([4]type{ f16, f32, f64, f128 }) |F| {
            const I = std.meta.Int(std.builtin.Signedness.unsigned, @bitSizeOf(F));
            const rand_int = prng.random().int(I);
            const rand_float = @as(F, @bitCast(rand_int));
            const serialized = std.fmt.bufPrint(&buf, "{}", .{rand_float}) catch unreachable;
            const deserialized = std.fmt.parseFloat(F, serialized) catch unreachable;
            try std.testing.expect(rand_int == @as(I, @bitCast(deserialized)));
        }
    }
}

tiehuis added a commit to tiehuis/zig that referenced this issue Mar 9, 2024
This replaces the errol backend with one based on ryu. The 128-bit
backend only is implemented. This supports all floating-point types and
does not use fp logic to print.

Closes ziglang#1181.
Closes ziglang#1299.
Closes ziglang#3612.
@andrewrk andrewrk modified the milestones: 0.15.0, 0.12.0 Mar 12, 2024
RossComputerGuy pushed a commit to ExpidusOS-archive/zig that referenced this issue Mar 20, 2024
This replaces the errol backend with one based on ryu. The 128-bit
backend only is implemented. This supports all floating-point types and
does not use fp logic to print.

Closes ziglang#1181.
Closes ziglang#1299.
Closes ziglang#3612.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Solving this issue will likely involve adding new logic or components to the codebase. standard library This issue involves writing Zig code for the standard library.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants