authorgravatar for hi@viri.moeviri <hi@viri.moe> 2022-04-01 15:17:24-06:00
committergravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2022-04-06 15:50:36+02:00
log5b8ac9821dd25c3e5282130b4d93d6c5b7debb08
tree5b616f4b873c383d7bbab81ebfa0e8d9338f451e
parent62f54aa39cb3dca3055033a57bc4626e94061aec

derive float constants in a generic way (#10133)


3 files changed, 143 insertions(+), 77 deletions(-)

lib/std/math.zig+38-62
......@@ -36,38 +36,44 @@ pub const sqrt2 = 1.414213562373095048801688724209698079;
3636/// 1/sqrt(2)
3737pub const sqrt1_2 = 0.707106781186547524400844362104849039;
3838
39pub const f128_true_min = @bitCast(f128, @as(u128, 0x00000000000000000000000000000001));
40pub const f128_min = @bitCast(f128, @as(u128, 0x00010000000000000000000000000000));
41pub const f128_max = @bitCast(f128, @as(u128, 0x7FFEFFFFFFFFFFFFFFFFFFFFFFFFFFFF));
42pub const f128_epsilon = @bitCast(f128, @as(u128, 0x3F8F0000000000000000000000000000));
43pub const f128_toint = 1.0 / f128_epsilon;
44
45// float.h details
46pub const f80_true_min = make_f80(.{ .fraction = 1, .exp = 0 });
47pub const f80_min = make_f80(.{ .fraction = 0x8000000000000000, .exp = 1 });
48pub const f80_max = make_f80(.{ .fraction = 0xFFFFFFFFFFFFFFFF, .exp = 0x7FFE });
49pub const f80_epsilon = make_f80(.{ .fraction = 0x8000000000000000, .exp = 0x3FC0 });
50pub const f80_toint = 1.0 / f80_epsilon;
51
52pub const f64_true_min = 4.94065645841246544177e-324;
53pub const f64_min = 2.2250738585072014e-308;
54pub const f64_max = 1.79769313486231570815e+308;
55pub const f64_epsilon = 2.22044604925031308085e-16;
56pub const f64_toint = 1.0 / f64_epsilon;
57
58pub const f32_true_min = 1.40129846432481707092e-45;
59pub const f32_min = 1.17549435082228750797e-38;
60pub const f32_max = 3.40282346638528859812e+38;
61pub const f32_epsilon = 1.1920928955078125e-07;
62pub const f32_toint = 1.0 / f32_epsilon;
63
64pub const f16_true_min = 0.000000059604644775390625; // 2**-24
65pub const f16_min = 0.00006103515625; // 2**-14
66pub const f16_max = 65504;
67pub const f16_epsilon = 0.0009765625; // 2**-10
68pub const f16_toint = 1.0 / f16_epsilon;
69
70pub const epsilon = @import("math/epsilon.zig").epsilon;
39pub const floatExponentBits = @import("math/float.zig").floatExponentBits;
40pub const floatMantissaBits = @import("math/float.zig").floatMantissaBits;
41pub const floatMantissaDigits = @import("math/float.zig").floatMantissaDigits;
42pub const floatExponentMin = @import("math/float.zig").floatExponentMin;
43pub const floatExponentMax = @import("math/float.zig").floatExponentMax;
44pub const floatTrueMin = @import("math/float.zig").floatTrueMin;
45pub const floatMin = @import("math/float.zig").floatMin;
46pub const floatMax = @import("math/float.zig").floatMax;
47pub const floatEps = @import("math/float.zig").floatEps;
48
49// TODO Replace with @compileError("deprecated for foobar") after 0.10.0 is released.
50pub const f16_true_min: comptime_float = floatTrueMin(f16); // prev: 0.000000059604644775390625
51pub const f32_true_min: comptime_float = floatTrueMin(f32); // prev: 1.40129846432481707092e-45
52pub const f64_true_min: comptime_float = floatTrueMin(f64); // prev: 4.94065645841246544177e-324
53pub const f80_true_min = floatTrueMin(f80); // prev: make_f80(.{ .fraction = 1, .exp = 0 })
54pub const f128_true_min = floatTrueMin(f128); // prev: @bitCast(f128, @as(u128, 0x00000000000000000000000000000001))
55pub const f16_min: comptime_float = floatMin(f16); // prev: 0.00006103515625
56pub const f32_min: comptime_float = floatMin(f32); // prev: 1.17549435082228750797e-38
57pub const f64_min: comptime_float = floatMin(f64); // prev: 2.2250738585072014e-308
58pub const f80_min = floatMin(f80); // prev: make_f80(.{ .fraction = 0x8000000000000000, .exp = 1 })
59pub const f128_min = floatMin(f128); // prev: @bitCast(f128, @as(u128, 0x00010000000000000000000000000000))
60pub const f16_max: comptime_float = floatMax(f16); // prev: 65504
61pub const f32_max: comptime_float = floatMax(f32); // prev: 3.40282346638528859812e+38
62pub const f64_max: comptime_float = floatMax(f64); // prev: 1.79769313486231570815e+308
63pub const f80_max = floatMax(f80); // prev: make_f80(.{ .fraction = 0xFFFFFFFFFFFFFFFF, .exp = 0x7FFE })
64pub const f128_max = floatMax(f128); // prev: @bitCast(f128, @as(u128, 0x7FFEFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
65pub const f16_epsilon: comptime_float = floatEps(f16); // prev: 0.0009765625
66pub const f32_epsilon: comptime_float = floatEps(f32); // prev: 1.1920928955078125e-07
67pub const f64_epsilon: comptime_float = floatEps(f64); // prev: 2.22044604925031308085e-16
68pub const f80_epsilon = floatEps(f80); // prev: make_f80(.{ .fraction = 0x8000000000000000, .exp = 0x3FC0 })
69pub const f128_epsilon = floatEps(f128); // prev: @bitCast(f128, @as(u128, 0x3F8F0000000000000000000000000000))
70pub const f16_toint: comptime_float = 1.0 / f16_epsilon; // same as before
71pub const f32_toint: comptime_float = 1.0 / f32_epsilon; // same as before
72pub const f64_toint: comptime_float = 1.0 / f64_epsilon; // same as before
73pub const f80_toint = 1.0 / f80_epsilon; // same as before
74pub const f128_toint = 1.0 / f128_epsilon; // same as before
75pub const epsilon = floatEps;
76// End of "soft deprecated" section
7177
7278pub const nan_u16 = @as(u16, 0x7C01);
7379pub const nan_f16 = @bitCast(f16, nan_u16);
......@@ -294,36 +300,6 @@ test {
294300 std.testing.refAllDecls(@This());
295301}
296302
297/// Returns the number of bits in the mantissa of floating point type
298/// T.
299pub fn floatMantissaBits(comptime T: type) comptime_int {
300 assert(@typeInfo(T) == .Float);
301
302 return switch (@typeInfo(T).Float.bits) {
303 16 => 10,
304 32 => 23,
305 64 => 52,
306 80 => 64,
307 128 => 112,
308 else => @compileError("unknown floating point type " ++ @typeName(T)),
309 };
310}
311
312/// Returns the number of bits in the exponent of floating point type
313/// T.
314pub fn floatExponentBits(comptime T: type) comptime_int {
315 assert(@typeInfo(T) == .Float);
316
317 return switch (@typeInfo(T).Float.bits) {
318 16 => 5,
319 32 => 8,
320 64 => 11,
321 80 => 15,
322 128 => 15,
323 else => @compileError("unknown floating point type " ++ @typeName(T)),
324 };
325}
326
327303/// Given two types, returns the smallest one which is capable of holding the
328304/// full range of the minimum value.
329305pub fn Min(comptime A: type, comptime B: type) type {
lib/std/math/epsilon.zig deleted-15
......@@ -1,15 +0,0 @@
1const math = @import("../math.zig");
2
3/// Returns the machine epsilon for type T.
4/// This is the smallest value of type T that satisfies the inequality 1.0 +
5/// epsilon != 1.0.
6pub fn epsilon(comptime T: type) T {
7 return switch (T) {
8 f16 => math.f16_epsilon,
9 f32 => math.f32_epsilon,
10 f64 => math.f64_epsilon,
11 f80 => math.f80_epsilon,
12 f128 => math.f128_epsilon,
13 else => @compileError("epsilon not implemented for " ++ @typeName(T)),
14 };
15}
lib/std/math/float.zig created+105
......@@ -0,0 +1,105 @@
1const std = @import("../std.zig");
2const assert = std.debug.assert;
3const expect = std.testing.expect;
4
5/// Creates a raw "1.0" mantissa for floating point type T. Used to dedupe f80 logic.
6fn mantissaOne(comptime T: type) comptime_int {
7 return if (floatMantissaDigits(T) == 64) 1 << 63 else 0;
8}
9
10/// Creates floating point type T from an unbiased exponent and raw mantissa.
11fn reconstructFloat(comptime T: type, exponent: comptime_int, mantissa: comptime_int) T {
12 const TBits = std.meta.Int(.unsigned, @bitSizeOf(T));
13 const biased_exponent = @as(TBits, exponent + floatExponentMax(T));
14 return @bitCast(T, (biased_exponent << floatMantissaBits(T)) | @as(TBits, mantissa));
15}
16
17/// Returns the number of bits in the exponent of floating point type T.
18pub fn floatExponentBits(comptime T: type) comptime_int {
19 assert(@typeInfo(T) == .Float);
20
21 return switch (@typeInfo(T).Float.bits) {
22 16 => 5,
23 32 => 8,
24 64 => 11,
25 80 => 15,
26 128 => 15,
27 else => @compileError("unknown floating point type " ++ @typeName(T)),
28 };
29}
30
31/// Returns the number of bits in the mantissa of floating point type T.
32pub fn floatMantissaBits(comptime T: type) comptime_int {
33 assert(@typeInfo(T) == .Float);
34
35 return switch (@typeInfo(T).Float.bits) {
36 16 => 10,
37 32 => 23,
38 64 => 52,
39 80 => 64,
40 128 => 112,
41 else => @compileError("unknown floating point type " ++ @typeName(T)),
42 };
43}
44
45/// Returns the number of binary digits in the mantissa of floating point type T.
46pub fn floatMantissaDigits(comptime T: type) comptime_int {
47 assert(@typeInfo(T) == .Float);
48
49 // standard IEEE floats have an implicit 0.m or 1.m integer part
50 // f80 is special and has an explicitly stored bit in the MSB
51 // this function corresponds to `MANT_DIG' constants from C
52 return switch (@typeInfo(T).Float.bits) {
53 16 => 11,
54 32 => 24,
55 64 => 53,
56 80 => 64,
57 128 => 113,
58 else => @compileError("unknown floating point type " ++ @typeName(T)),
59 };
60}
61
62/// Returns the minimum exponent that can represent
63/// a normalised value in floating point type T.
64pub fn floatExponentMin(comptime T: type) comptime_int {
65 return -floatExponentMax(T) + 1;
66}
67
68/// Returns the maximum exponent that can represent
69/// a normalised value in floating point type T.
70pub fn floatExponentMax(comptime T: type) comptime_int {
71 return (1 << (floatExponentBits(T) - 1)) - 1;
72}
73
74/// Returns the smallest subnormal number representable in floating point type T.
75pub fn floatTrueMin(comptime T: type) T {
76 return reconstructFloat(T, floatExponentMin(T) - 1, 1);
77}
78
79/// Returns the smallest normal number representable in floating point type T.
80pub fn floatMin(comptime T: type) T {
81 return reconstructFloat(T, floatExponentMin(T), mantissaOne(T));
82}
83
84/// Returns the largest normal number representable in floating point type T.
85pub fn floatMax(comptime T: type) T {
86 const all1s_mantissa = (1 << floatMantissaBits(T)) - 1;
87 return reconstructFloat(T, floatExponentMax(T), all1s_mantissa);
88}
89
90/// Returns the machine epsilon of floating point type T.
91pub fn floatEps(comptime T: type) T {
92 return reconstructFloat(T, -(floatMantissaDigits(T) - 1), mantissaOne(T));
93}
94
95test "std.math.float" {
96 inline for ([_]type{ f16, f32, f64, f80, f128, c_longdouble }) |T| {
97 // (1 +) for the sign bit, since it is separate from the other bits
98 const size = 1 + floatExponentBits(T) + floatMantissaBits(T);
99 try expect(@bitSizeOf(T) == size);
100
101 // for machine epsilon, assert expmin <= -prec <= expmax
102 try expect(floatExponentMin(T) <= -(floatMantissaDigits(T) - 1));
103 try expect(-(floatMantissaDigits(T) - 1) <= floatExponentMax(T));
104 }
105}