Commit 5ae838d105
Changed files (2)
lib
std
fmt
parse_float
lib/std/fmt/parse_float/parse_float.zig
@@ -1,66 +0,0 @@
-const std = @import("std");
-const parse = @import("parse.zig");
-const convertFast = @import("convert_fast.zig").convertFast;
-const convertEiselLemire = @import("convert_eisel_lemire.zig").convertEiselLemire;
-const convertSlow = @import("convert_slow.zig").convertSlow;
-const convertHex = @import("convert_hex.zig").convertHex;
-
-pub const ParseFloatError = error{
- InvalidCharacter,
-};
-
-pub fn parseFloat(comptime T: type, s: []const u8) ParseFloatError!T {
- if (@typeInfo(T) != .Float) {
- @compileError("Cannot parse a float into a non-floating point type.");
- }
-
- if (T == f80) {
- @compileError("TODO support parsing float to f80");
- }
-
- if (s.len == 0) {
- return error.InvalidCharacter;
- }
-
- var i: usize = 0;
- const negative = s[i] == '-';
- if (s[i] == '-' or s[i] == '+') {
- i += 1;
- }
- if (s.len == i) {
- return error.InvalidCharacter;
- }
-
- const n = parse.parseNumber(T, s[i..], negative) orelse {
- return parse.parseInfOrNan(T, s[i..], negative) orelse error.InvalidCharacter;
- };
-
- if (n.hex) {
- return convertHex(T, n);
- }
-
- if (convertFast(T, n)) |f| {
- return f;
- }
-
- if (T == f16 or T == f32 or T == f64) {
- // If significant digits were truncated, then we can have rounding error
- // only if `mantissa + 1` produces a different result. We also avoid
- // redundantly using the Eisel-Lemire algorithm if it was unable to
- // correctly round on the first pass.
- if (convertEiselLemire(T, n.exponent, n.mantissa)) |bf| {
- if (!n.many_digits) {
- return bf.toFloat(T, n.negative);
- }
- if (convertEiselLemire(T, n.exponent, n.mantissa + 1)) |bf2| {
- if (bf.eql(bf2)) {
- return bf.toFloat(T, n.negative);
- }
- }
- }
- }
-
- // Unable to correctly round the float using the Eisel-Lemire algorithm.
- // Fallback to a slower, but always correct algorithm.
- return convertSlow(T, s[i..]).toFloat(T, negative);
-}
lib/std/fmt/parse_float.zig
@@ -1,7 +1,4 @@
-pub const parseFloat = @import("parse_float/parse_float.zig").parseFloat;
-pub const ParseFloatError = @import("parse_float/parse_float.zig").ParseFloatError;
-
-const std = @import("std");
+const std = @import("../std.zig");
const math = std.math;
const testing = std.testing;
const expect = testing.expect;
@@ -9,10 +6,75 @@ const expectEqual = testing.expectEqual;
const expectError = testing.expectError;
const approxEqAbs = std.math.approxEqAbs;
const epsilon = 1e-7;
+const parse = @import("parse_float/parse.zig");
+const convertHex = @import("parse_float/convert_hex.zig").convertHex;
+const convertFast = @import("parse_float/convert_fast.zig").convertFast;
+const convertEiselLemire = @import("parse_float/convert_eisel_lemire.zig").convertEiselLemire;
+const convertSlow = @import("parse_float/convert_slow.zig").convertSlow;
+
+pub const ParseFloatError = error{
+ InvalidCharacter,
+};
+
+pub fn parseFloat(comptime T: type, s: []const u8) ParseFloatError!T {
+ if (@typeInfo(T) != .Float) {
+ @compileError("Cannot parse a float into a non-floating point type.");
+ }
+
+ if (T == f80) {
+ @compileError("TODO support parsing float to f80");
+ }
+
+ if (s.len == 0) {
+ return error.InvalidCharacter;
+ }
+
+ var i: usize = 0;
+ const negative = s[i] == '-';
+ if (s[i] == '-' or s[i] == '+') {
+ i += 1;
+ }
+ if (s.len == i) {
+ return error.InvalidCharacter;
+ }
+
+ const n = parse.parseNumber(T, s[i..], negative) orelse {
+ return parse.parseInfOrNan(T, s[i..], negative) orelse error.InvalidCharacter;
+ };
+
+ if (n.hex) {
+ return convertHex(T, n);
+ }
+
+ if (convertFast(T, n)) |f| {
+ return f;
+ }
+
+ if (T == f16 or T == f32 or T == f64) {
+ // If significant digits were truncated, then we can have rounding error
+ // only if `mantissa + 1` produces a different result. We also avoid
+ // redundantly using the Eisel-Lemire algorithm if it was unable to
+ // correctly round on the first pass.
+ if (convertEiselLemire(T, n.exponent, n.mantissa)) |bf| {
+ if (!n.many_digits) {
+ return bf.toFloat(T, n.negative);
+ }
+ if (convertEiselLemire(T, n.exponent, n.mantissa + 1)) |bf2| {
+ if (bf.eql(bf2)) {
+ return bf.toFloat(T, n.negative);
+ }
+ }
+ }
+ }
+
+ // Unable to correctly round the float using the Eisel-Lemire algorithm.
+ // Fallback to a slower, but always correct algorithm.
+ return convertSlow(T, s[i..]).toFloat(T, negative);
+}
// See https://github.com/tiehuis/parse-number-fxx-test-data for a wider-selection of test-data.
-test "parseFloat" {
+test parseFloat {
inline for ([_]type{ f16, f32, f64, f128 }) |T| {
try testing.expectError(error.InvalidCharacter, parseFloat(T, ""));
try testing.expectError(error.InvalidCharacter, parseFloat(T, " 1"));