| ... | ... | @@ -84,10 +84,6 @@ const Z96 = struct { |
| 84 | 84 | w += u64(d.d2) -% u64(s.d2); |
| 85 | 85 | d.d2 = @truncate(u32, w); |
| 86 | 86 | } |
| 87 | | |
| 88 | | fn dump(d: Z96) void { |
| 89 | | std.debug.warn("{} {} {}\n", d.d0, d.d1, d.d2); |
| 90 | | } |
| 91 | 87 | }; |
| 92 | 88 | |
| 93 | 89 | const FloatRepr = struct { |
| ... | ... | @@ -178,7 +174,6 @@ fn convertRepr(comptime T: type, n: FloatRepr) T { |
| 178 | 174 | } |
| 179 | 175 | |
| 180 | 176 | const State = enum { |
| 181 | | SkipLeadingWhitespace, |
| 182 | 177 | MaybeSign, |
| 183 | 178 | LeadingMantissaZeros, |
| 184 | 179 | LeadingFractionalZeros, |
| ... | ... | @@ -187,7 +182,6 @@ const State = enum { |
| 187 | 182 | ExponentSign, |
| 188 | 183 | LeadingExponentZeros, |
| 189 | 184 | Exponent, |
| 190 | | Stop, |
| 191 | 185 | }; |
| 192 | 186 | |
| 193 | 187 | const ParseResult = enum { |
| ... | ... | @@ -206,27 +200,19 @@ inline fn isSpace(c: u8) bool { |
| 206 | 200 | return (c >= 0x09 and c <= 0x13) or c == 0x20; |
| 207 | 201 | } |
| 208 | 202 | |
| 209 | | fn parseRepr(s: []const u8, n: *FloatRepr) ParseResult { |
| 203 | fn parseRepr(s: []const u8, n: *FloatRepr) !ParseResult { |
| 210 | 204 | var digit_index: usize = 0; |
| 211 | 205 | var negative = false; |
| 212 | 206 | var negative_exp = false; |
| 213 | 207 | var exponent: i32 = 0; |
| 214 | 208 | |
| 215 | | var state = State.SkipLeadingWhitespace; |
| 209 | var state = State.MaybeSign; |
| 216 | 210 | |
| 217 | 211 | var i: usize = 0; |
| 218 | | loop: while (state != State.Stop and i < s.len) { |
| 212 | loop: while (i < s.len) { |
| 219 | 213 | const c = s[i]; |
| 220 | 214 | |
| 221 | 215 | switch (state) { |
| 222 | | State.SkipLeadingWhitespace => { |
| 223 | | if (isSpace(c)) { |
| 224 | | i += 1; |
| 225 | | } else { |
| 226 | | state = State.MaybeSign; |
| 227 | | } |
| 228 | | }, |
| 229 | | |
| 230 | 216 | State.MaybeSign => { |
| 231 | 217 | state = State.LeadingMantissaZeros; |
| 232 | 218 | |
| ... | ... | @@ -238,7 +224,7 @@ fn parseRepr(s: []const u8, n: *FloatRepr) ParseResult { |
| 238 | 224 | } else if (isDigit(c) or c == '.') { |
| 239 | 225 | // continue |
| 240 | 226 | } else { |
| 241 | | state = State.Stop; |
| 227 | return error.InvalidCharacter; |
| 242 | 228 | } |
| 243 | 229 | }, |
| 244 | 230 | |
| ... | ... | @@ -329,11 +315,9 @@ fn parseRepr(s: []const u8, n: *FloatRepr) ParseResult { |
| 329 | 315 | |
| 330 | 316 | i += 1; |
| 331 | 317 | } else { |
| 332 | | state = State.Stop; |
| 318 | return error.InvalidCharacter; |
| 333 | 319 | } |
| 334 | 320 | }, |
| 335 | | |
| 336 | | State.Stop => break :loop, |
| 337 | 321 | } |
| 338 | 322 | } |
| 339 | 323 | |
| ... | ... | @@ -371,12 +355,10 @@ fn caseInEql(a: []const u8, b: []const u8) bool { |
| 371 | 355 | return true; |
| 372 | 356 | } |
| 373 | 357 | |
| 374 | | pub fn parseFloat(comptime T: type, s: []const u8) T { |
| 375 | | var r = FloatRepr{ |
| 376 | | .negative = false, |
| 377 | | .exponent = 0, |
| 378 | | .mantissa = 0, |
| 379 | | }; |
| 358 | pub fn parseFloat(comptime T: type, s: []const u8) !T { |
| 359 | if (s.len == 0) { |
| 360 | return error.InvalidCharacter; |
| 361 | } |
| 380 | 362 | |
| 381 | 363 | if (caseInEql(s, "nan")) { |
| 382 | 364 | return std.math.nan(T); |
| ... | ... | @@ -386,7 +368,13 @@ pub fn parseFloat(comptime T: type, s: []const u8) T { |
| 386 | 368 | return -std.math.inf(T); |
| 387 | 369 | } |
| 388 | 370 | |
| 389 | | return switch (parseRepr(s, &r)) { |
| 371 | var r = FloatRepr{ |
| 372 | .negative = false, |
| 373 | .exponent = 0, |
| 374 | .mantissa = 0, |
| 375 | }; |
| 376 | |
| 377 | return switch (try parseRepr(s, &r)) { |
| 390 | 378 | ParseResult.Ok => convertRepr(T, r), |
| 391 | 379 | ParseResult.PlusZero => 0.0, |
| 392 | 380 | ParseResult.MinusZero => -T(0.0), |
| ... | ... | @@ -396,30 +384,37 @@ pub fn parseFloat(comptime T: type, s: []const u8) T { |
| 396 | 384 | } |
| 397 | 385 | |
| 398 | 386 | test "fmt.parseFloat" { |
| 399 | | const assert = std.debug.assert; |
| 387 | const testing = std.testing; |
| 388 | const expect = testing.expect; |
| 389 | const expectEqual = testing.expectEqual; |
| 400 | 390 | const approxEq = std.math.approxEq; |
| 401 | 391 | const epsilon = 1e-7; |
| 402 | 392 | |
| 403 | | inline for ([]type{ f32, f64, f128 }) |T| { |
| 393 | inline for ([]type{ f16, f32, f64, f128 }) |T| { |
| 404 | 394 | const Z = @IntType(false, T.bit_count); |
| 405 | 395 | |
| 406 | | assert(parseFloat(T, "0") == 0.0); |
| 407 | | assert(parseFloat(T, "+0") == 0.0); |
| 408 | | assert(parseFloat(T, "-0") == 0.0); |
| 396 | testing.expectError(error.InvalidCharacter, parseFloat(T, "")); |
| 397 | testing.expectError(error.InvalidCharacter, parseFloat(T, " 1")); |
| 398 | testing.expectError(error.InvalidCharacter, parseFloat(T, "1abc")); |
| 399 | |
| 400 | expectEqual(try parseFloat(T, "0"), 0.0); |
| 401 | expectEqual((try parseFloat(T, "0")), 0.0); |
| 402 | expectEqual((try parseFloat(T, "+0")), 0.0); |
| 403 | expectEqual((try parseFloat(T, "-0")), 0.0); |
| 409 | 404 | |
| 410 | | assert(approxEq(T, parseFloat(T, "3.141"), 3.141, epsilon)); |
| 411 | | assert(approxEq(T, parseFloat(T, "-3.141"), -3.141, epsilon)); |
| 405 | expect(approxEq(T, try parseFloat(T, "3.141"), 3.141, epsilon)); |
| 406 | expect(approxEq(T, try parseFloat(T, "-3.141"), -3.141, epsilon)); |
| 412 | 407 | |
| 413 | | assert(parseFloat(T, "1e-700") == 0); |
| 414 | | assert(parseFloat(T, "1e+700") == std.math.inf(T)); |
| 408 | expectEqual((try parseFloat(T, "1e-700")), 0); |
| 409 | expectEqual((try parseFloat(T, "1e+700")), std.math.inf(T)); |
| 415 | 410 | |
| 416 | | assert(@bitCast(Z, parseFloat(T, "nAn")) == @bitCast(Z, std.math.nan(T))); |
| 417 | | assert(parseFloat(T, "inF") == std.math.inf(T)); |
| 418 | | assert(parseFloat(T, "-INF") == -std.math.inf(T)); |
| 411 | expectEqual(@bitCast(Z, try parseFloat(T, "nAn")), @bitCast(Z, std.math.nan(T))); |
| 412 | expectEqual((try parseFloat(T, "inF")), std.math.inf(T)); |
| 413 | expectEqual((try parseFloat(T, "-INF")), -std.math.inf(T)); |
| 419 | 414 | |
| 420 | 415 | if (T != f16) { |
| 421 | | assert(approxEq(T, parseFloat(T, "123142.1"), 123142.1, epsilon)); |
| 422 | | assert(approxEq(T, parseFloat(T, "-123142.1124"), T(-123142.1124), epsilon)); |
| 416 | expect(approxEq(T, try parseFloat(T, "123142.1"), 123142.1, epsilon)); |
| 417 | expect(approxEq(T, try parseFloat(T, "-123142.1124"), T(-123142.1124), epsilon)); |
| 423 | 418 | } |
| 424 | 419 | } |
| 425 | 420 | } |