| ... | @@ -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); |