| author | |
| committer | |
| log | bd282d6cca226c0b02af193f9c3cf0da5f6ea46d |
| tree | 5286470c43ef6c7f6530bf8518b0356e44a6ca3a |
| parent | 22b7312460c89f8fc9dad9674776d4ca3b40acd7 |
| parent | 30cfc0ab2c56ad73dca9b9935731d10010c93b32 |
| signature |
improve std.math f16 support14 files changed, 191 insertions(+), 2 deletions(-)
std/math/copysign.zig+18| ... | @@ -4,12 +4,22 @@ const assert = std.debug.assert; | ... | @@ -4,12 +4,22 @@ const assert = std.debug.assert; |
| 4 | 4 | ||
| 5 | pub fn copysign(comptime T: type, x: T, y: T) T { | 5 | pub fn copysign(comptime T: type, x: T, y: T) T { |
| 6 | return switch (T) { | 6 | return switch (T) { |
| 7 | f16 => copysign16(x, y), | ||
| 7 | f32 => copysign32(x, y), | 8 | f32 => copysign32(x, y), |
| 8 | f64 => copysign64(x, y), | 9 | f64 => copysign64(x, y), |
| 9 | else => @compileError("copysign not implemented for " ++ @typeName(T)), | 10 | else => @compileError("copysign not implemented for " ++ @typeName(T)), |
| 10 | }; | 11 | }; |
| 11 | } | 12 | } |
| 12 | 13 | ||
| 14 | fn copysign16(x: f16, y: f16) f16 { | ||
| 15 | const ux = @bitCast(u16, x); | ||
| 16 | const uy = @bitCast(u16, y); | ||
| 17 | |||
| 18 | const h1 = ux & (@maxValue(u16) / 2); | ||
| 19 | const h2 = uy & (u16(1) << 15); | ||
| 20 | return @bitCast(f16, h1 | h2); | ||
| 21 | } | ||
| 22 | |||
| 13 | fn copysign32(x: f32, y: f32) f32 { | 23 | fn copysign32(x: f32, y: f32) f32 { |
| 14 | const ux = @bitCast(u32, x); | 24 | const ux = @bitCast(u32, x); |
| 15 | const uy = @bitCast(u32, y); | 25 | const uy = @bitCast(u32, y); |
| ... | @@ -29,10 +39,18 @@ fn copysign64(x: f64, y: f64) f64 { | ... | @@ -29,10 +39,18 @@ fn copysign64(x: f64, y: f64) f64 { |
| 29 | } | 39 | } |
| 30 | 40 | ||
| 31 | test "math.copysign" { | 41 | test "math.copysign" { |
| 42 | assert(copysign(f16, 1.0, 1.0) == copysign16(1.0, 1.0)); | ||
| 32 | assert(copysign(f32, 1.0, 1.0) == copysign32(1.0, 1.0)); | 43 | assert(copysign(f32, 1.0, 1.0) == copysign32(1.0, 1.0)); |
| 33 | assert(copysign(f64, 1.0, 1.0) == copysign64(1.0, 1.0)); | 44 | assert(copysign(f64, 1.0, 1.0) == copysign64(1.0, 1.0)); |
| 34 | } | 45 | } |
| 35 | 46 | ||
| 47 | test "math.copysign16" { | ||
| 48 | assert(copysign16(5.0, 1.0) == 5.0); | ||
| 49 | assert(copysign16(5.0, -1.0) == -5.0); | ||
| 50 | assert(copysign16(-5.0, -1.0) == -5.0); | ||
| 51 | assert(copysign16(-5.0, 1.0) == 5.0); | ||
| 52 | } | ||
| 53 | |||
| 36 | test "math.copysign32" { | 54 | test "math.copysign32" { |
| 37 | assert(copysign32(5.0, 1.0) == 5.0); | 55 | assert(copysign32(5.0, 1.0) == 5.0); |
| 38 | assert(copysign32(5.0, -1.0) == -5.0); | 56 | assert(copysign32(5.0, -1.0) == -5.0); |
std/math/fabs.zig+19| ... | @@ -10,12 +10,19 @@ const assert = std.debug.assert; | ... | @@ -10,12 +10,19 @@ const assert = std.debug.assert; |
| 10 | pub fn fabs(x: var) @typeOf(x) { | 10 | pub fn fabs(x: var) @typeOf(x) { |
| 11 | const T = @typeOf(x); | 11 | const T = @typeOf(x); |
| 12 | return switch (T) { | 12 | return switch (T) { |
| 13 | f16 => fabs16(x), | ||
| 13 | f32 => fabs32(x), | 14 | f32 => fabs32(x), |
| 14 | f64 => fabs64(x), | 15 | f64 => fabs64(x), |
| 15 | else => @compileError("fabs not implemented for " ++ @typeName(T)), | 16 | else => @compileError("fabs not implemented for " ++ @typeName(T)), |
| 16 | }; | 17 | }; |
| 17 | } | 18 | } |
| 18 | 19 | ||
| 20 | fn fabs16(x: f16) f16 { | ||
| 21 | var u = @bitCast(u16, x); | ||
| 22 | u &= 0x7FFF; | ||
| 23 | return @bitCast(f16, u); | ||
| 24 | } | ||
| 25 | |||
| 19 | fn fabs32(x: f32) f32 { | 26 | fn fabs32(x: f32) f32 { |
| 20 | var u = @bitCast(u32, x); | 27 | var u = @bitCast(u32, x); |
| 21 | u &= 0x7FFFFFFF; | 28 | u &= 0x7FFFFFFF; |
| ... | @@ -29,10 +36,16 @@ fn fabs64(x: f64) f64 { | ... | @@ -29,10 +36,16 @@ fn fabs64(x: f64) f64 { |
| 29 | } | 36 | } |
| 30 | 37 | ||
| 31 | test "math.fabs" { | 38 | test "math.fabs" { |
| 39 | assert(fabs(f16(1.0)) == fabs16(1.0)); | ||
| 32 | assert(fabs(f32(1.0)) == fabs32(1.0)); | 40 | assert(fabs(f32(1.0)) == fabs32(1.0)); |
| 33 | assert(fabs(f64(1.0)) == fabs64(1.0)); | 41 | assert(fabs(f64(1.0)) == fabs64(1.0)); |
| 34 | } | 42 | } |
| 35 | 43 | ||
| 44 | test "math.fabs16" { | ||
| 45 | assert(fabs16(1.0) == 1.0); | ||
| 46 | assert(fabs16(-1.0) == 1.0); | ||
| 47 | } | ||
| 48 | |||
| 36 | test "math.fabs32" { | 49 | test "math.fabs32" { |
| 37 | assert(fabs32(1.0) == 1.0); | 50 | assert(fabs32(1.0) == 1.0); |
| 38 | assert(fabs32(-1.0) == 1.0); | 51 | assert(fabs32(-1.0) == 1.0); |
| ... | @@ -43,6 +56,12 @@ test "math.fabs64" { | ... | @@ -43,6 +56,12 @@ test "math.fabs64" { |
| 43 | assert(fabs64(-1.0) == 1.0); | 56 | assert(fabs64(-1.0) == 1.0); |
| 44 | } | 57 | } |
| 45 | 58 | ||
| 59 | test "math.fabs16.special" { | ||
| 60 | assert(math.isPositiveInf(fabs(math.inf(f16)))); | ||
| 61 | assert(math.isPositiveInf(fabs(-math.inf(f16)))); | ||
| 62 | assert(math.isNan(fabs(math.nan(f16)))); | ||
| 63 | } | ||
| 64 | |||
| 46 | test "math.fabs32.special" { | 65 | test "math.fabs32.special" { |
| 47 | assert(math.isPositiveInf(fabs(math.inf(f32)))); | 66 | assert(math.isPositiveInf(fabs(math.inf(f32)))); |
| 48 | assert(math.isPositiveInf(fabs(-math.inf(f32)))); | 67 | assert(math.isPositiveInf(fabs(-math.inf(f32)))); |
std/math/floor.zig+50| ... | @@ -12,12 +12,47 @@ const math = std.math; | ... | @@ -12,12 +12,47 @@ const math = std.math; |
| 12 | pub fn floor(x: var) @typeOf(x) { | 12 | pub fn floor(x: var) @typeOf(x) { |
| 13 | const T = @typeOf(x); | 13 | const T = @typeOf(x); |
| 14 | return switch (T) { | 14 | return switch (T) { |
| 15 | f16 => floor16(x), | ||
| 15 | f32 => floor32(x), | 16 | f32 => floor32(x), |
| 16 | f64 => floor64(x), | 17 | f64 => floor64(x), |
| 17 | else => @compileError("floor not implemented for " ++ @typeName(T)), | 18 | else => @compileError("floor not implemented for " ++ @typeName(T)), |
| 18 | }; | 19 | }; |
| 19 | } | 20 | } |
| 20 | 21 | ||
| 22 | fn floor16(x: f16) f16 { | ||
| 23 | var u = @bitCast(u16, x); | ||
| 24 | const e = @intCast(i16, (u >> 10) & 31) - 15; | ||
| 25 | var m: u16 = undefined; | ||
| 26 | |||
| 27 | // TODO: Shouldn't need this explicit check. | ||
| 28 | if (x == 0.0) { | ||
| 29 | return x; | ||
| 30 | } | ||
| 31 | |||
| 32 | if (e >= 10) { | ||
| 33 | return x; | ||
| 34 | } | ||
| 35 | |||
| 36 | if (e >= 0) { | ||
| 37 | m = u16(1023) >> @intCast(u4, e); | ||
| 38 | if (u & m == 0) { | ||
| 39 | return x; | ||
| 40 | } | ||
| 41 | math.forceEval(x + 0x1.0p120); | ||
| 42 | if (u >> 15 != 0) { | ||
| 43 | u += m; | ||
| 44 | } | ||
| 45 | return @bitCast(f16, u & ~m); | ||
| 46 | } else { | ||
| 47 | math.forceEval(x + 0x1.0p120); | ||
| 48 | if (u >> 15 == 0) { | ||
| 49 | return 0.0; | ||
| 50 | } else { | ||
| 51 | return -1.0; | ||
| 52 | } | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 21 | fn floor32(x: f32) f32 { | 56 | fn floor32(x: f32) f32 { |
| 22 | var u = @bitCast(u32, x); | 57 | var u = @bitCast(u32, x); |
| 23 | const e = @intCast(i32, (u >> 23) & 0xFF) - 0x7F; | 58 | const e = @intCast(i32, (u >> 23) & 0xFF) - 0x7F; |
| ... | @@ -84,10 +119,17 @@ fn floor64(x: f64) f64 { | ... | @@ -84,10 +119,17 @@ fn floor64(x: f64) f64 { |
| 84 | } | 119 | } |
| 85 | 120 | ||
| 86 | test "math.floor" { | 121 | test "math.floor" { |
| 122 | assert(floor(f16(1.3)) == floor16(1.3)); | ||
| 87 | assert(floor(f32(1.3)) == floor32(1.3)); | 123 | assert(floor(f32(1.3)) == floor32(1.3)); |
| 88 | assert(floor(f64(1.3)) == floor64(1.3)); | 124 | assert(floor(f64(1.3)) == floor64(1.3)); |
| 89 | } | 125 | } |
| 90 | 126 | ||
| 127 | test "math.floor16" { | ||
| 128 | assert(floor16(1.3) == 1.0); | ||
| 129 | assert(floor16(-1.3) == -2.0); | ||
| 130 | assert(floor16(0.2) == 0.0); | ||
| 131 | } | ||
| 132 | |||
| 91 | test "math.floor32" { | 133 | test "math.floor32" { |
| 92 | assert(floor32(1.3) == 1.0); | 134 | assert(floor32(1.3) == 1.0); |
| 93 | assert(floor32(-1.3) == -2.0); | 135 | assert(floor32(-1.3) == -2.0); |
| ... | @@ -100,6 +142,14 @@ test "math.floor64" { | ... | @@ -100,6 +142,14 @@ test "math.floor64" { |
| 100 | assert(floor64(0.2) == 0.0); | 142 | assert(floor64(0.2) == 0.0); |
| 101 | } | 143 | } |
| 102 | 144 | ||
| 145 | test "math.floor16.special" { | ||
| 146 | assert(floor16(0.0) == 0.0); | ||
| 147 | assert(floor16(-0.0) == -0.0); | ||
| 148 | assert(math.isPositiveInf(floor16(math.inf(f16)))); | ||
| 149 | assert(math.isNegativeInf(floor16(-math.inf(f16)))); | ||
| 150 | assert(math.isNan(floor16(math.nan(f16)))); | ||
| 151 | } | ||
| 152 | |||
| 103 | test "math.floor32.special" { | 153 | test "math.floor32.special" { |
| 104 | assert(floor32(0.0) == 0.0); | 154 | assert(floor32(0.0) == 0.0); |
| 105 | assert(floor32(-0.0) == -0.0); | 155 | assert(floor32(-0.0) == -0.0); |
std/math/index.zig+17| ... | @@ -19,6 +19,18 @@ pub const f32_max = 3.40282346638528859812e+38; | ... | @@ -19,6 +19,18 @@ pub const f32_max = 3.40282346638528859812e+38; |
| 19 | pub const f32_epsilon = 1.1920928955078125e-07; | 19 | pub const f32_epsilon = 1.1920928955078125e-07; |
| 20 | pub const f32_toint = 1.0 / f32_epsilon; | 20 | pub const f32_toint = 1.0 / f32_epsilon; |
| 21 | 21 | ||
| 22 | pub const f16_true_min = 0.000000059604644775390625; // 2**-24 | ||
| 23 | pub const f16_min = 0.00006103515625; // 2**-14 | ||
| 24 | pub const f16_max = 65504; | ||
| 25 | pub const f16_epsilon = 0.0009765625; // 2**-10 | ||
| 26 | pub const f16_toint = 1.0 / f16_epsilon; | ||
| 27 | |||
| 28 | pub const nan_u16 = u16(0x7C01); | ||
| 29 | pub const nan_f16 = @bitCast(f16, nan_u16); | ||
| 30 | |||
| 31 | pub const inf_u16 = u16(0x7C00); | ||
| 32 | pub const inf_f16 = @bitCast(f16, inf_u16); | ||
| 33 | |||
| 22 | pub const nan_u32 = u32(0x7F800001); | 34 | pub const nan_u32 = u32(0x7F800001); |
| 23 | pub const nan_f32 = @bitCast(f32, nan_u32); | 35 | pub const nan_f32 = @bitCast(f32, nan_u32); |
| 24 | 36 | ||
| ... | @@ -44,6 +56,11 @@ pub fn approxEq(comptime T: type, x: T, y: T, epsilon: T) bool { | ... | @@ -44,6 +56,11 @@ pub fn approxEq(comptime T: type, x: T, y: T, epsilon: T) bool { |
| 44 | pub fn forceEval(value: var) void { | 56 | pub fn forceEval(value: var) void { |
| 45 | const T = @typeOf(value); | 57 | const T = @typeOf(value); |
| 46 | switch (T) { | 58 | switch (T) { |
| 59 | f16 => { | ||
| 60 | var x: f16 = undefined; | ||
| 61 | const p = @ptrCast(*volatile f16, &x); | ||
| 62 | p.* = x; | ||
| 63 | }, | ||
| 47 | f32 => { | 64 | f32 => { |
| 48 | var x: f32 = undefined; | 65 | var x: f32 = undefined; |
| 49 | const p = @ptrCast(*volatile f32, &x); | 66 | const p = @ptrCast(*volatile f32, &x); |
std/math/inf.zig+1-1| ... | @@ -1,9 +1,9 @@ | ... | @@ -1,9 +1,9 @@ |
| 1 | const std = @import("../index.zig"); | 1 | const std = @import("../index.zig"); |
| 2 | const math = std.math; | 2 | const math = std.math; |
| 3 | const assert = std.debug.assert; | ||
| 4 | 3 | ||
| 5 | pub fn inf(comptime T: type) T { | 4 | pub fn inf(comptime T: type) T { |
| 6 | return switch (T) { | 5 | return switch (T) { |
| 6 | f16 => @bitCast(f16, math.inf_u16), | ||
| 7 | f32 => @bitCast(f32, math.inf_u32), | 7 | f32 => @bitCast(f32, math.inf_u32), |
| 8 | f64 => @bitCast(f64, math.inf_u64), | 8 | f64 => @bitCast(f64, math.inf_u64), |
| 9 | else => @compileError("inf not implemented for " ++ @typeName(T)), | 9 | else => @compileError("inf not implemented for " ++ @typeName(T)), |
std/math/isfinite.zig+8| ... | @@ -5,6 +5,10 @@ const assert = std.debug.assert; | ... | @@ -5,6 +5,10 @@ const assert = std.debug.assert; |
| 5 | pub fn isFinite(x: var) bool { | 5 | pub fn isFinite(x: var) bool { |
| 6 | const T = @typeOf(x); | 6 | const T = @typeOf(x); |
| 7 | switch (T) { | 7 | switch (T) { |
| 8 | f16 => { | ||
| 9 | const bits = @bitCast(u16, x); | ||
| 10 | return bits & 0x7FFF < 0x7C00; | ||
| 11 | }, | ||
| 8 | f32 => { | 12 | f32 => { |
| 9 | const bits = @bitCast(u32, x); | 13 | const bits = @bitCast(u32, x); |
| 10 | return bits & 0x7FFFFFFF < 0x7F800000; | 14 | return bits & 0x7FFFFFFF < 0x7F800000; |
| ... | @@ -20,10 +24,14 @@ pub fn isFinite(x: var) bool { | ... | @@ -20,10 +24,14 @@ pub fn isFinite(x: var) bool { |
| 20 | } | 24 | } |
| 21 | 25 | ||
| 22 | test "math.isFinite" { | 26 | test "math.isFinite" { |
| 27 | assert(isFinite(f16(0.0))); | ||
| 28 | assert(isFinite(f16(-0.0))); | ||
| 23 | assert(isFinite(f32(0.0))); | 29 | assert(isFinite(f32(0.0))); |
| 24 | assert(isFinite(f32(-0.0))); | 30 | assert(isFinite(f32(-0.0))); |
| 25 | assert(isFinite(f64(0.0))); | 31 | assert(isFinite(f64(0.0))); |
| 26 | assert(isFinite(f64(-0.0))); | 32 | assert(isFinite(f64(-0.0))); |
| 33 | assert(!isFinite(math.inf(f16))); | ||
| 34 | assert(!isFinite(-math.inf(f16))); | ||
| 27 | assert(!isFinite(math.inf(f32))); | 35 | assert(!isFinite(math.inf(f32))); |
| 28 | assert(!isFinite(-math.inf(f32))); | 36 | assert(!isFinite(-math.inf(f32))); |
| 29 | assert(!isFinite(math.inf(f64))); | 37 | assert(!isFinite(math.inf(f64))); |
std/math/isinf.zig+22| ... | @@ -5,6 +5,10 @@ const assert = std.debug.assert; | ... | @@ -5,6 +5,10 @@ const assert = std.debug.assert; |
| 5 | pub fn isInf(x: var) bool { | 5 | pub fn isInf(x: var) bool { |
| 6 | const T = @typeOf(x); | 6 | const T = @typeOf(x); |
| 7 | switch (T) { | 7 | switch (T) { |
| 8 | f16 => { | ||
| 9 | const bits = @bitCast(u16, x); | ||
| 10 | return bits & 0x7FFF == 0x7C00; | ||
| 11 | }, | ||
| 8 | f32 => { | 12 | f32 => { |
| 9 | const bits = @bitCast(u32, x); | 13 | const bits = @bitCast(u32, x); |
| 10 | return bits & 0x7FFFFFFF == 0x7F800000; | 14 | return bits & 0x7FFFFFFF == 0x7F800000; |
| ... | @@ -22,6 +26,9 @@ pub fn isInf(x: var) bool { | ... | @@ -22,6 +26,9 @@ pub fn isInf(x: var) bool { |
| 22 | pub fn isPositiveInf(x: var) bool { | 26 | pub fn isPositiveInf(x: var) bool { |
| 23 | const T = @typeOf(x); | 27 | const T = @typeOf(x); |
| 24 | switch (T) { | 28 | switch (T) { |
| 29 | f16 => { | ||
| 30 | return @bitCast(u16, x) == 0x7C00; | ||
| 31 | }, | ||
| 25 | f32 => { | 32 | f32 => { |
| 26 | return @bitCast(u32, x) == 0x7F800000; | 33 | return @bitCast(u32, x) == 0x7F800000; |
| 27 | }, | 34 | }, |
| ... | @@ -37,6 +44,9 @@ pub fn isPositiveInf(x: var) bool { | ... | @@ -37,6 +44,9 @@ pub fn isPositiveInf(x: var) bool { |
| 37 | pub fn isNegativeInf(x: var) bool { | 44 | pub fn isNegativeInf(x: var) bool { |
| 38 | const T = @typeOf(x); | 45 | const T = @typeOf(x); |
| 39 | switch (T) { | 46 | switch (T) { |
| 47 | f16 => { | ||
| 48 | return @bitCast(u16, x) == 0xFC00; | ||
| 49 | }, | ||
| 40 | f32 => { | 50 | f32 => { |
| 41 | return @bitCast(u32, x) == 0xFF800000; | 51 | return @bitCast(u32, x) == 0xFF800000; |
| 42 | }, | 52 | }, |
| ... | @@ -50,10 +60,14 @@ pub fn isNegativeInf(x: var) bool { | ... | @@ -50,10 +60,14 @@ pub fn isNegativeInf(x: var) bool { |
| 50 | } | 60 | } |
| 51 | 61 | ||
| 52 | test "math.isInf" { | 62 | test "math.isInf" { |
| 63 | assert(!isInf(f16(0.0))); | ||
| 64 | assert(!isInf(f16(-0.0))); | ||
| 53 | assert(!isInf(f32(0.0))); | 65 | assert(!isInf(f32(0.0))); |
| 54 | assert(!isInf(f32(-0.0))); | 66 | assert(!isInf(f32(-0.0))); |
| 55 | assert(!isInf(f64(0.0))); | 67 | assert(!isInf(f64(0.0))); |
| 56 | assert(!isInf(f64(-0.0))); | 68 | assert(!isInf(f64(-0.0))); |
| 69 | assert(isInf(math.inf(f16))); | ||
| 70 | assert(isInf(-math.inf(f16))); | ||
| 57 | assert(isInf(math.inf(f32))); | 71 | assert(isInf(math.inf(f32))); |
| 58 | assert(isInf(-math.inf(f32))); | 72 | assert(isInf(-math.inf(f32))); |
| 59 | assert(isInf(math.inf(f64))); | 73 | assert(isInf(math.inf(f64))); |
| ... | @@ -61,10 +75,14 @@ test "math.isInf" { | ... | @@ -61,10 +75,14 @@ test "math.isInf" { |
| 61 | } | 75 | } |
| 62 | 76 | ||
| 63 | test "math.isPositiveInf" { | 77 | test "math.isPositiveInf" { |
| 78 | assert(!isPositiveInf(f16(0.0))); | ||
| 79 | assert(!isPositiveInf(f16(-0.0))); | ||
| 64 | assert(!isPositiveInf(f32(0.0))); | 80 | assert(!isPositiveInf(f32(0.0))); |
| 65 | assert(!isPositiveInf(f32(-0.0))); | 81 | assert(!isPositiveInf(f32(-0.0))); |
| 66 | assert(!isPositiveInf(f64(0.0))); | 82 | assert(!isPositiveInf(f64(0.0))); |
| 67 | assert(!isPositiveInf(f64(-0.0))); | 83 | assert(!isPositiveInf(f64(-0.0))); |
| 84 | assert(isPositiveInf(math.inf(f16))); | ||
| 85 | assert(!isPositiveInf(-math.inf(f16))); | ||
| 68 | assert(isPositiveInf(math.inf(f32))); | 86 | assert(isPositiveInf(math.inf(f32))); |
| 69 | assert(!isPositiveInf(-math.inf(f32))); | 87 | assert(!isPositiveInf(-math.inf(f32))); |
| 70 | assert(isPositiveInf(math.inf(f64))); | 88 | assert(isPositiveInf(math.inf(f64))); |
| ... | @@ -72,10 +90,14 @@ test "math.isPositiveInf" { | ... | @@ -72,10 +90,14 @@ test "math.isPositiveInf" { |
| 72 | } | 90 | } |
| 73 | 91 | ||
| 74 | test "math.isNegativeInf" { | 92 | test "math.isNegativeInf" { |
| 93 | assert(!isNegativeInf(f16(0.0))); | ||
| 94 | assert(!isNegativeInf(f16(-0.0))); | ||
| 75 | assert(!isNegativeInf(f32(0.0))); | 95 | assert(!isNegativeInf(f32(0.0))); |
| 76 | assert(!isNegativeInf(f32(-0.0))); | 96 | assert(!isNegativeInf(f32(-0.0))); |
| 77 | assert(!isNegativeInf(f64(0.0))); | 97 | assert(!isNegativeInf(f64(0.0))); |
| 78 | assert(!isNegativeInf(f64(-0.0))); | 98 | assert(!isNegativeInf(f64(-0.0))); |
| 99 | assert(!isNegativeInf(math.inf(f16))); | ||
| 100 | assert(isNegativeInf(-math.inf(f16))); | ||
| 79 | assert(!isNegativeInf(math.inf(f32))); | 101 | assert(!isNegativeInf(math.inf(f32))); |
| 80 | assert(isNegativeInf(-math.inf(f32))); | 102 | assert(isNegativeInf(-math.inf(f32))); |
| 81 | assert(!isNegativeInf(math.inf(f64))); | 103 | assert(!isNegativeInf(math.inf(f64))); |
std/math/isnan.zig+6| ... | @@ -5,6 +5,10 @@ const assert = std.debug.assert; | ... | @@ -5,6 +5,10 @@ const assert = std.debug.assert; |
| 5 | pub fn isNan(x: var) bool { | 5 | pub fn isNan(x: var) bool { |
| 6 | const T = @typeOf(x); | 6 | const T = @typeOf(x); |
| 7 | switch (T) { | 7 | switch (T) { |
| 8 | f16 => { | ||
| 9 | const bits = @bitCast(u16, x); | ||
| 10 | return (bits & 0x7fff) > 0x7c00; | ||
| 11 | }, | ||
| 8 | f32 => { | 12 | f32 => { |
| 9 | const bits = @bitCast(u32, x); | 13 | const bits = @bitCast(u32, x); |
| 10 | return bits & 0x7FFFFFFF > 0x7F800000; | 14 | return bits & 0x7FFFFFFF > 0x7F800000; |
| ... | @@ -26,8 +30,10 @@ pub fn isSignalNan(x: var) bool { | ... | @@ -26,8 +30,10 @@ pub fn isSignalNan(x: var) bool { |
| 26 | } | 30 | } |
| 27 | 31 | ||
| 28 | test "math.isNan" { | 32 | test "math.isNan" { |
| 33 | assert(isNan(math.nan(f16))); | ||
| 29 | assert(isNan(math.nan(f32))); | 34 | assert(isNan(math.nan(f32))); |
| 30 | assert(isNan(math.nan(f64))); | 35 | assert(isNan(math.nan(f64))); |
| 36 | assert(!isNan(f16(1.0))); | ||
| 31 | assert(!isNan(f32(1.0))); | 37 | assert(!isNan(f32(1.0))); |
| 32 | assert(!isNan(f64(1.0))); | 38 | assert(!isNan(f64(1.0))); |
| 33 | } | 39 | } |
std/math/isnormal.zig+9| ... | @@ -5,6 +5,10 @@ const assert = std.debug.assert; | ... | @@ -5,6 +5,10 @@ const assert = std.debug.assert; |
| 5 | pub fn isNormal(x: var) bool { | 5 | pub fn isNormal(x: var) bool { |
| 6 | const T = @typeOf(x); | 6 | const T = @typeOf(x); |
| 7 | switch (T) { | 7 | switch (T) { |
| 8 | f16 => { | ||
| 9 | const bits = @bitCast(u16, x); | ||
| 10 | return (bits + 1024) & 0x7FFF >= 2048; | ||
| 11 | }, | ||
| 8 | f32 => { | 12 | f32 => { |
| 9 | const bits = @bitCast(u32, x); | 13 | const bits = @bitCast(u32, x); |
| 10 | return (bits + 0x00800000) & 0x7FFFFFFF >= 0x01000000; | 14 | return (bits + 0x00800000) & 0x7FFFFFFF >= 0x01000000; |
| ... | @@ -20,8 +24,13 @@ pub fn isNormal(x: var) bool { | ... | @@ -20,8 +24,13 @@ pub fn isNormal(x: var) bool { |
| 20 | } | 24 | } |
| 21 | 25 | ||
| 22 | test "math.isNormal" { | 26 | test "math.isNormal" { |
| 27 | assert(!isNormal(math.nan(f16))); | ||
| 23 | assert(!isNormal(math.nan(f32))); | 28 | assert(!isNormal(math.nan(f32))); |
| 24 | assert(!isNormal(math.nan(f64))); | 29 | assert(!isNormal(math.nan(f64))); |
| 30 | assert(!isNormal(f16(0))); | ||
| 31 | assert(!isNormal(f32(0))); | ||
| 32 | assert(!isNormal(f64(0))); | ||
| 33 | assert(isNormal(f16(1.0))); | ||
| 25 | assert(isNormal(f32(1.0))); | 34 | assert(isNormal(f32(1.0))); |
| 26 | assert(isNormal(f64(1.0))); | 35 | assert(isNormal(f64(1.0))); |
| 27 | } | 36 | } |
std/math/nan.zig+2| ... | @@ -2,6 +2,7 @@ const math = @import("index.zig"); | ... | @@ -2,6 +2,7 @@ const math = @import("index.zig"); |
| 2 | 2 | ||
| 3 | pub fn nan(comptime T: type) T { | 3 | pub fn nan(comptime T: type) T { |
| 4 | return switch (T) { | 4 | return switch (T) { |
| 5 | f16 => @bitCast(f16, math.nan_u16), | ||
| 5 | f32 => @bitCast(f32, math.nan_u32), | 6 | f32 => @bitCast(f32, math.nan_u32), |
| 6 | f64 => @bitCast(f64, math.nan_u64), | 7 | f64 => @bitCast(f64, math.nan_u64), |
| 7 | else => @compileError("nan not implemented for " ++ @typeName(T)), | 8 | else => @compileError("nan not implemented for " ++ @typeName(T)), |
| ... | @@ -12,6 +13,7 @@ pub fn nan(comptime T: type) T { | ... | @@ -12,6 +13,7 @@ pub fn nan(comptime T: type) T { |
| 12 | // representation in the future when required. | 13 | // representation in the future when required. |
| 13 | pub fn snan(comptime T: type) T { | 14 | pub fn snan(comptime T: type) T { |
| 14 | return switch (T) { | 15 | return switch (T) { |
| 16 | f16 => @bitCast(f16, math.nan_u16), | ||
| 15 | f32 => @bitCast(f32, math.nan_u32), | 17 | f32 => @bitCast(f32, math.nan_u32), |
| 16 | f64 => @bitCast(f64, math.nan_u64), | 18 | f64 => @bitCast(f64, math.nan_u64), |
| 17 | else => @compileError("snan not implemented for " ++ @typeName(T)), | 19 | else => @compileError("snan not implemented for " ++ @typeName(T)), |
std/math/signbit.zig+12| ... | @@ -5,12 +5,18 @@ const assert = std.debug.assert; | ... | @@ -5,12 +5,18 @@ const assert = std.debug.assert; |
| 5 | pub fn signbit(x: var) bool { | 5 | pub fn signbit(x: var) bool { |
| 6 | const T = @typeOf(x); | 6 | const T = @typeOf(x); |
| 7 | return switch (T) { | 7 | return switch (T) { |
| 8 | f16 => signbit16(x), | ||
| 8 | f32 => signbit32(x), | 9 | f32 => signbit32(x), |
| 9 | f64 => signbit64(x), | 10 | f64 => signbit64(x), |
| 10 | else => @compileError("signbit not implemented for " ++ @typeName(T)), | 11 | else => @compileError("signbit not implemented for " ++ @typeName(T)), |
| 11 | }; | 12 | }; |
| 12 | } | 13 | } |
| 13 | 14 | ||
| 15 | fn signbit16(x: f16) bool { | ||
| 16 | const bits = @bitCast(u16, x); | ||
| 17 | return bits >> 15 != 0; | ||
| 18 | } | ||
| 19 | |||
| 14 | fn signbit32(x: f32) bool { | 20 | fn signbit32(x: f32) bool { |
| 15 | const bits = @bitCast(u32, x); | 21 | const bits = @bitCast(u32, x); |
| 16 | return bits >> 31 != 0; | 22 | return bits >> 31 != 0; |
| ... | @@ -22,10 +28,16 @@ fn signbit64(x: f64) bool { | ... | @@ -22,10 +28,16 @@ fn signbit64(x: f64) bool { |
| 22 | } | 28 | } |
| 23 | 29 | ||
| 24 | test "math.signbit" { | 30 | test "math.signbit" { |
| 31 | assert(signbit(f16(4.0)) == signbit16(4.0)); | ||
| 25 | assert(signbit(f32(4.0)) == signbit32(4.0)); | 32 | assert(signbit(f32(4.0)) == signbit32(4.0)); |
| 26 | assert(signbit(f64(4.0)) == signbit64(4.0)); | 33 | assert(signbit(f64(4.0)) == signbit64(4.0)); |
| 27 | } | 34 | } |
| 28 | 35 | ||
| 36 | test "math.signbit16" { | ||
| 37 | assert(!signbit16(4.0)); | ||
| 38 | assert(signbit16(-3.0)); | ||
| 39 | } | ||
| 40 | |||
| 29 | test "math.signbit32" { | 41 | test "math.signbit32" { |
| 30 | assert(!signbit32(4.0)); | 42 | assert(!signbit32(4.0)); |
| 31 | assert(signbit32(-3.0)); | 43 | assert(signbit32(-3.0)); |
std/math/sqrt.zig+23| ... | @@ -31,10 +31,25 @@ pub fn sqrt(x: var) (if (@typeId(@typeOf(x)) == TypeId.Int) @IntType(false, @typ | ... | @@ -31,10 +31,25 @@ pub fn sqrt(x: var) (if (@typeId(@typeOf(x)) == TypeId.Int) @IntType(false, @typ |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | test "math.sqrt" { | 33 | test "math.sqrt" { |
| 34 | assert(sqrt(f16(0.0)) == @sqrt(f16, 0.0)); | ||
| 34 | assert(sqrt(f32(0.0)) == @sqrt(f32, 0.0)); | 35 | assert(sqrt(f32(0.0)) == @sqrt(f32, 0.0)); |
| 35 | assert(sqrt(f64(0.0)) == @sqrt(f64, 0.0)); | 36 | assert(sqrt(f64(0.0)) == @sqrt(f64, 0.0)); |
| 36 | } | 37 | } |
| 37 | 38 | ||
| 39 | test "math.sqrt16" { | ||
| 40 | const epsilon = 0.000001; | ||
| 41 | |||
| 42 | assert(@sqrt(f16, 0.0) == 0.0); | ||
| 43 | assert(math.approxEq(f16, @sqrt(f16, 2.0), 1.414214, epsilon)); | ||
| 44 | assert(math.approxEq(f16, @sqrt(f16, 3.6), 1.897367, epsilon)); | ||
| 45 | assert(@sqrt(f16, 4.0) == 2.0); | ||
| 46 | assert(math.approxEq(f16, @sqrt(f16, 7.539840), 2.745877, epsilon)); | ||
| 47 | assert(math.approxEq(f16, @sqrt(f16, 19.230934), 4.385309, epsilon)); | ||
| 48 | assert(@sqrt(f16, 64.0) == 8.0); | ||
| 49 | assert(math.approxEq(f16, @sqrt(f16, 64.1), 8.006248, epsilon)); | ||
| 50 | assert(math.approxEq(f16, @sqrt(f16, 8942.230469), 94.563370, epsilon)); | ||
| 51 | } | ||
| 52 | |||
| 38 | test "math.sqrt32" { | 53 | test "math.sqrt32" { |
| 39 | const epsilon = 0.000001; | 54 | const epsilon = 0.000001; |
| 40 | 55 | ||
| ... | @@ -63,6 +78,14 @@ test "math.sqrt64" { | ... | @@ -63,6 +78,14 @@ test "math.sqrt64" { |
| 63 | assert(math.approxEq(f64, @sqrt(f64, 8942.230469), 94.563367, epsilon)); | 78 | assert(math.approxEq(f64, @sqrt(f64, 8942.230469), 94.563367, epsilon)); |
| 64 | } | 79 | } |
| 65 | 80 | ||
| 81 | test "math.sqrt16.special" { | ||
| 82 | assert(math.isPositiveInf(@sqrt(f16, math.inf(f16)))); | ||
| 83 | assert(@sqrt(f16, 0.0) == 0.0); | ||
| 84 | assert(@sqrt(f16, -0.0) == -0.0); | ||
| 85 | assert(math.isNan(@sqrt(f16, -1.0))); | ||
| 86 | assert(math.isNan(@sqrt(f16, math.nan(f16)))); | ||
| 87 | } | ||
| 88 | |||
| 66 | test "math.sqrt32.special" { | 89 | test "math.sqrt32.special" { |
| 67 | assert(math.isPositiveInf(@sqrt(f32, math.inf(f32)))); | 90 | assert(math.isPositiveInf(@sqrt(f32, math.inf(f32)))); |
| 68 | assert(@sqrt(f32, 0.0) == 0.0); | 91 | assert(@sqrt(f32, 0.0) == 0.0); |
std/special/builtin.zig+3-1| ... | @@ -210,7 +210,9 @@ fn generic_fmod(comptime T: type, x: T, y: T) T { | ... | @@ -210,7 +210,9 @@ fn generic_fmod(comptime T: type, x: T, y: T) T { |
| 210 | } | 210 | } |
| 211 | 211 | ||
| 212 | fn isNan(comptime T: type, bits: T) bool { | 212 | fn isNan(comptime T: type, bits: T) bool { |
| 213 | if (T == u32) { | 213 | if (T == u16) { |
| 214 | return (bits & 0x7fff) > 0x7c00; | ||
| 215 | } else if (T == u32) { | ||
| 214 | return (bits & 0x7fffffff) > 0x7f800000; | 216 | return (bits & 0x7fffffff) > 0x7f800000; |
| 215 | } else if (T == u64) { | 217 | } else if (T == u64) { |
| 216 | return (bits & (@maxValue(u64) >> 1)) > (u64(0x7ff) << 52); | 218 | return (bits & (@maxValue(u64) >> 1)) > (u64(0x7ff) << 52); |
std/special/compiler_rt/extendXfYf2_test.zig+1| ... | @@ -88,6 +88,7 @@ test "extenddftf2" { | ... | @@ -88,6 +88,7 @@ test "extenddftf2" { |
| 88 | test "extendhfsf2" { | 88 | test "extendhfsf2" { |
| 89 | test__extendhfsf2(0x7e00, 0x7fc00000); // qNaN | 89 | test__extendhfsf2(0x7e00, 0x7fc00000); // qNaN |
| 90 | test__extendhfsf2(0x7f00, 0x7fe00000); // sNaN | 90 | test__extendhfsf2(0x7f00, 0x7fe00000); // sNaN |
| 91 | test__extendhfsf2(0x7c01, 0x7f802000); // sNaN | ||
| 91 | 92 | ||
| 92 | test__extendhfsf2(0, 0); // 0 | 93 | test__extendhfsf2(0, 0); // 0 |
| 93 | test__extendhfsf2(0x8000, 0x80000000); // -0 | 94 | test__extendhfsf2(0x8000, 0x80000000); // -0 |