Trying to parse string to f128 fails

I doubt that I would ever need a float this large, but I would still like to know why my parse function works for all float types except f128.

const std = @import("std");
const meta = std.meta;
const ArrayList = std.ArrayList;
const TypeInfo = std.builtin.TypeInfo;
const print = std.debug.print;
const ParseError = error{ParseError} || anyerror;

pub fn parse(comptime T: type, buffer: []const u8) ParseError!T {
    const typeInfo = @typeInfo(T);
    const typeId = std.builtin.TypeId;
    _ = typeId;
    return switch (typeInfo) {
        .Int => std.fmt.parseInt(T, buffer, 10),
        .Float => std.fmt.parseFloat(T, buffer),
        .Enum => |e| {
            inline for (e.fields) |field| {
                if (std.mem.eql(u8, field.name, buffer)) {
                    return @as(T, @enumFromInt(field.value));
                }
            }
            return ParseError.ParseError;
        },
        .Bool => std.mem.eql(u8, buffer, "true"),
        else => {
            @compileError("Tried to parse an unsupported type: " ++ @typeName(T));
        },
    };
}

pub fn main() !void {
    print("Type info of f128: {any}\n", .{@typeInfo(f128)});
    var parseTest = try parse(f128, "100.0");
    print("parseTest: {d} the type is {any}\n", .{ parseTest, @TypeOf(parseTest) });
}

This is the output:

error: expected type 'f64', found 'f128'
    var x = @as(f64, value);
                     ^~~~~
referenced by:
    formatFloatValue__anon_8701: /home/clinton/zig-linux-x86_64-0.12.0-dev.80+014d88ef6/lib/std/fmt.zig:802:27
    formatValue__anon_8700: /home/clinton/zig-linux-x86_64-0.12.0-dev.80+014d88ef6/lib/std/fmt.zig:732:58
    remaining reference traces hidden; use '-freference-trace' to see all reference traces

Why is it expecting a f64 in this case instead of just reading the buffer as f128?
Any help or clarification would be appreciated.

It is not a problem in your parse function. It’s actually a problem with formating(→printing) the f128 float.
(By the way, if you pass -freference-trace to the compile command on an error like this you will get a more detailed trace)

This is a known issue: Implement proper f128 float printing · Issue #1181 · ziglang/zig · GitHub
The workaround would be to cast the solution:

print("...{d}...", .{@as(f64, @floatCast(parseTest)), ...});
3 Likes

First of all, your code will not compile with recent 0.12-dev Zig compiler due to infamous

tmp/t.zig:32:9: error: local variable is never mutated
    var parseTest = try parse(f128, "100.0");
        ^~~~~~~~~
tmp/t.zig:32:9: note: consider using 'const'

Secondly, you do not need {d}. Replace it with {}. Here is the version of main() that compiles and runs OK

pub fn main() !void {
    print("Type info of f128: {any}\n", .{@typeInfo(f128)});
    const parseTest = try parse(f128, "100.0");
    print("parseTest: {} the type is {}\n", .{ parseTest, @TypeOf(parseTest) });
}
1 Like

Interesting enough, when I pass -freference-trace to the run command it fixes the issue entirely.
Now I get the expected output

Type info of f128: builtin.Type{ .Float = builtin.Type.Float{ .bits = 128 } }
parseTest: 1.0e+02 the type is f128

[Process exited 0]

Edit: Nvm, I didn’t realize i used {any} instead of {d}.