| ... | @@ -3,11 +3,12 @@ | ... | @@ -3,11 +3,12 @@ |
| 3 | // | 3 | // |
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/atanf.c | 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/atanf.c |
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/atan.c | 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/atan.c |
| | 6 | // https://git.musl-libc.org/cgit/musl/tree/src/math/atanl.c |
| 6 | | 7 | |
| 7 | const std = @import("../std.zig"); | 8 | const std = @import("../std.zig"); |
| 8 | const math = std.math; | 9 | const math = std.math; |
| 9 | const mem = std.mem; | 10 | const mem = std.mem; |
| 10 | const expect = std.testing.expect; | 11 | const testing = std.testing; |
| 11 | | 12 | |
| 12 | /// Returns the arc-tangent of x. | 13 | /// Returns the arc-tangent of x. |
| 13 | /// | 14 | /// |
| ... | @@ -17,28 +18,100 @@ const expect = std.testing.expect; | ... | @@ -17,28 +18,100 @@ const expect = std.testing.expect; |
| 17 | pub fn atan(x: anytype) @TypeOf(x) { | 18 | pub fn atan(x: anytype) @TypeOf(x) { |
| 18 | const T = @TypeOf(x); | 19 | const T = @TypeOf(x); |
| 19 | return switch (T) { | 20 | return switch (T) { |
| 20 | f32 => atan32(x), | 21 | f16 => atanBinary16(x), |
| 21 | f64 => atan64(x), | 22 | f32 => atanBinary32(x), |
| | 23 | f64 => atanBinary64(x), |
| | 24 | f80 => atanExtended80(x), |
| | 25 | f128 => atanBinary128(x), |
| 22 | else => @compileError("atan not implemented for " ++ @typeName(T)), | 26 | else => @compileError("atan not implemented for " ++ @typeName(T)), |
| 23 | }; | 27 | }; |
| 24 | } | 28 | } |
| 25 | | 29 | |
| 26 | fn atan32(x_: f32) f32 { | 30 | fn atanBinary16(x: f16) f16 { |
| 27 | const atanhi = [_]f32{ | 31 | const atanhi: []const f32 = &.{ |
| 28 | 4.6364760399e-01, // atan(0.5)hi | 32 | 4.6364760399e-01, // atan(0.5)hi 0x3eed6338 |
| 29 | 7.8539812565e-01, // atan(1.0)hi | 33 | 7.8539812565e-01, // atan(1.0)hi 0x3f490fda |
| 30 | 9.8279368877e-01, // atan(1.5)hi | 34 | 9.8279368877e-01, // atan(1.5)hi 0x3f7b985e |
| 31 | 1.5707962513e+00, // atan(inf)hi | 35 | 1.5707962513e+00, // atan(inf)hi 0x3fc90fda |
| | 36 | }; |
| | 37 | const aT: []const f32 = &.{ |
| | 38 | 0x1.fffcccp-1, |
| | 39 | -0x1.52e8ccp-2, |
| | 40 | 0x1.522336p-3, |
| 32 | }; | 41 | }; |
| 33 | | 42 | |
| 34 | const atanlo = [_]f32{ | 43 | const hx: u16 = @bitCast(x); |
| 35 | 5.0121582440e-09, // atan(0.5)lo | 44 | const ix = hx & 0x7fff; |
| 36 | 3.7748947079e-08, // atan(1.0)lo | 45 | const sign = (hx >> 15) != 0; |
| 37 | 3.4473217170e-08, // atan(1.5)lo | 46 | // if |x| >= 2^11 |
| 38 | 7.5497894159e-08, // atan(inf)lo | 47 | if (ix >= 0x6800) { |
| | 48 | if (math.isNan(x)) { |
| | 49 | return x; |
| | 50 | } |
| | 51 | const z = atanhi[3] + 0x1p-120; |
| | 52 | return @floatCast(if (sign) -z else z); |
| | 53 | } |
| | 54 | const x_: f32, const id: ?usize = blk: { |
| | 55 | // |x| < 0.4375 |
| | 56 | if (ix < 0x3700) { |
| | 57 | // |x| < 2^(-6) |
| | 58 | if (ix < 0x2400) { |
| | 59 | if (ix < 0x400) { |
| | 60 | // raise underflow for subnormal x |
| | 61 | mem.doNotOptimizeAway(x * x); |
| | 62 | } |
| | 63 | return x; |
| | 64 | } |
| | 65 | break :blk .{ @floatCast(x), null }; |
| | 66 | } else { |
| | 67 | const x_: f32 = @floatCast(@abs(x)); |
| | 68 | // |x| < 1.1875 |
| | 69 | if (ix < 0x3cc0) { |
| | 70 | // 7/16 <= |x| < 11/16 |
| | 71 | if (ix < 0x3980) { |
| | 72 | break :blk .{ (2.0 * x_ - 1.0) / (2.0 + x_), 0 }; |
| | 73 | } |
| | 74 | // 11/16 <= |x| < 19/16 |
| | 75 | else { |
| | 76 | break :blk .{ (x_ - 1.0) / (x_ + 1.0), 1 }; |
| | 77 | } |
| | 78 | } else { |
| | 79 | // |x| < 2.4375 |
| | 80 | if (ix < 0x40e0) { |
| | 81 | break :blk .{ (x_ - 1.5) / (1.0 + 1.5 * x_), 2 }; |
| | 82 | } |
| | 83 | // 2.4375 <= |x| < 2^11 |
| | 84 | else { |
| | 85 | break :blk .{ -1.0 / x_, 3 }; |
| | 86 | } |
| | 87 | } |
| | 88 | } |
| 39 | }; | 89 | }; |
| | 90 | // end of argument reduction |
| | 91 | const z = x_ * x_; |
| | 92 | const s = aT[0] + z * (aT[1] + z * aT[2]); |
| | 93 | if (id) |id_| { |
| | 94 | const z_ = atanhi[id_] + x_ * s; |
| | 95 | return @floatCast(if (sign) -z_ else z_); |
| | 96 | } else { |
| | 97 | return @floatCast(x_ * s); |
| | 98 | } |
| | 99 | } |
| 40 | | 100 | |
| 41 | const aT = [_]f32{ | 101 | fn atanBinary32(x: f32) f32 { |
| | 102 | const atanhi: []const f32 = &.{ |
| | 103 | 4.6364760399e-01, // atan(0.5)hi 0x3eed6338 |
| | 104 | 7.8539812565e-01, // atan(1.0)hi 0x3f490fda |
| | 105 | 9.8279368877e-01, // atan(1.5)hi 0x3f7b985e |
| | 106 | 1.5707962513e+00, // atan(inf)hi 0x3fc90fda |
| | 107 | }; |
| | 108 | const atanlo: []const f32 = &.{ |
| | 109 | 5.0121582440e-09, // atan(0.5)lo 0x31ac3769 |
| | 110 | 3.7748947079e-08, // atan(1.0)lo 0x33222168 |
| | 111 | 3.4473217170e-08, // atan(1.5)lo 0x33140fb4 |
| | 112 | 7.5497894159e-08, // atan(inf)lo 0x33a22168 |
| | 113 | }; |
| | 114 | const aT: []const f32 = &.{ |
| 42 | 3.3333328366e-01, | 115 | 3.3333328366e-01, |
| 43 | -1.9999158382e-01, | 116 | -1.9999158382e-01, |
| 44 | 1.4253635705e-01, | 117 | 1.4253635705e-01, |
| ... | @@ -46,211 +119,463 @@ fn atan32(x_: f32) f32 { | ... | @@ -46,211 +119,463 @@ fn atan32(x_: f32) f32 { |
| 46 | 6.1687607318e-02, | 119 | 6.1687607318e-02, |
| 47 | }; | 120 | }; |
| 48 | | 121 | |
| 49 | var x = x_; | 122 | const hx: u32 = @bitCast(x); |
| 50 | var ix: u32 = @as(u32, @bitCast(x)); | 123 | const ix = hx & 0x7fff_ffff; |
| 51 | const sign = ix >> 31; | 124 | const sign = (hx >> 31) != 0; |
| 52 | ix &= 0x7FFFFFFF; | 125 | // if |x| >= 2^26 |
| 53 | | 126 | if (ix >= 0x4c80_0000) { |
| 54 | // |x| >= 2^26 | | |
| 55 | if (ix >= 0x4C800000) { | | |
| 56 | if (math.isNan(x)) { | 127 | if (math.isNan(x)) { |
| 57 | return x; | 128 | return x; |
| 58 | } else { | | |
| 59 | const z = atanhi[3] + 0x1.0p-120; | | |
| 60 | return if (sign != 0) -z else z; | | |
| 61 | } | 129 | } |
| | 130 | const z = atanhi[3] + 0x1p-120; |
| | 131 | return if (sign) -z else z; |
| 62 | } | 132 | } |
| 63 | | 133 | const x_, const id: ?usize = blk: { |
| 64 | var id: ?usize = undefined; | 134 | // |x| < 0.4375 |
| 65 | | 135 | if (ix < 0x3ee00000) { |
| 66 | // |x| < 0.4375 | 136 | // |x| < 2^(-12) |
| 67 | if (ix < 0x3EE00000) { | 137 | if (ix < 0x39800000) { |
| 68 | // |x| < 2^(-12) | 138 | if (ix < 0x00800000) { |
| 69 | if (ix < 0x39800000) { | 139 | // raise underflow for subnormal x |
| 70 | if (ix < 0x00800000) { | 140 | mem.doNotOptimizeAway(x * x); |
| 71 | mem.doNotOptimizeAway(x * x); | 141 | } |
| 72 | } | 142 | return x; |
| 73 | return x; | | |
| 74 | } | | |
| 75 | id = null; | | |
| 76 | } else { | | |
| 77 | x = @abs(x); | | |
| 78 | // |x| < 1.1875 | | |
| 79 | if (ix < 0x3F980000) { | | |
| 80 | // 7/16 <= |x| < 11/16 | | |
| 81 | if (ix < 0x3F300000) { | | |
| 82 | id = 0; | | |
| 83 | x = (2.0 * x - 1.0) / (2.0 + x); | | |
| 84 | } | | |
| 85 | // 11/16 <= |x| < 19/16 | | |
| 86 | else { | | |
| 87 | id = 1; | | |
| 88 | x = (x - 1.0) / (x + 1.0); | | |
| 89 | } | 143 | } |
| | 144 | break :blk .{ x, null }; |
| 90 | } else { | 145 | } else { |
| 91 | // |x| < 2.4375 | 146 | const x_ = @abs(x); |
| 92 | if (ix < 0x401C0000) { | 147 | // |x| < 1.1875 |
| 93 | id = 2; | 148 | if (ix < 0x3f98_0000) { |
| 94 | x = (x - 1.5) / (1.0 + 1.5 * x); | 149 | // 7/16 <= |x| < 11/16 |
| 95 | } | 150 | if (ix < 0x3f30_0000) { |
| 96 | // 2.4375 <= |x| < 2^26 | 151 | break :blk .{ (2.0 * x_ - 1.0) / (2.0 + x_), 0 }; |
| 97 | else { | 152 | } |
| 98 | id = 3; | 153 | // 11/16 <= |x| < 19/16 |
| 99 | x = -1.0 / x; | 154 | else { |
| | 155 | break :blk .{ (x_ - 1.0) / (x_ + 1.0), 1 }; |
| | 156 | } |
| | 157 | } else { |
| | 158 | // |x| < 2.4375 |
| | 159 | if (ix < 0x401c_0000) { |
| | 160 | break :blk .{ (x_ - 1.5) / (1.0 + 1.5 * x_), 2 }; |
| | 161 | } |
| | 162 | // 2.4375 <= |x| < 2^26 |
| | 163 | else { |
| | 164 | break :blk .{ -1.0 / x_, 3 }; |
| | 165 | } |
| 100 | } | 166 | } |
| 101 | } | 167 | } |
| 102 | } | 168 | }; |
| 103 | | 169 | // end of argument reduction |
| 104 | const z = x * x; | 170 | const z = x_ * x_; |
| 105 | const w = z * z; | 171 | const w = z * z; |
| | 172 | // break sum from i=0 to 10 aT[i]z^(i+1) into odd and even poly |
| 106 | const s1 = z * (aT[0] + w * (aT[2] + w * aT[4])); | 173 | const s1 = z * (aT[0] + w * (aT[2] + w * aT[4])); |
| 107 | const s2 = w * (aT[1] + w * aT[3]); | 174 | const s2 = w * (aT[1] + w * aT[3]); |
| 108 | | 175 | if (id) |id_| { |
| 109 | if (id) |id_value| { | 176 | const z_ = atanhi[id_] - ((x_ * (s1 + s2) - atanlo[id_]) - x_); |
| 110 | const zz = atanhi[id_value] - ((x * (s1 + s2) - atanlo[id_value]) - x); | 177 | return if (sign) -z_ else z_; |
| 111 | return if (sign != 0) -zz else zz; | | |
| 112 | } else { | 178 | } else { |
| 113 | return x - x * (s1 + s2); | 179 | return x_ - x_ * (s1 + s2); |
| 114 | } | 180 | } |
| 115 | } | 181 | } |
| 116 | | 182 | |
| 117 | fn atan64(x_: f64) f64 { | 183 | fn atanBinary64(x: f64) f64 { |
| 118 | const atanhi = [_]f64{ | 184 | const atanhi: []const f64 = &.{ |
| 119 | 4.63647609000806093515e-01, // atan(0.5)hi | 185 | 4.63647609000806093515e-01, // atan(0.5)hi 0x3FDDAC67, 0x0561BB4F |
| 120 | 7.85398163397448278999e-01, // atan(1.0)hi | 186 | 7.85398163397448278999e-01, // atan(1.0)hi 0x3FE921FB, 0x54442D18 |
| 121 | 9.82793723247329054082e-01, // atan(1.5)hi | 187 | 9.82793723247329054082e-01, // atan(1.5)hi 0x3FEF730B, 0xD281F69B |
| 122 | 1.57079632679489655800e+00, // atan(inf)hi | 188 | 1.57079632679489655800e+00, // atan(inf)hi 0x3FF921FB, 0x54442D18 |
| 123 | }; | 189 | }; |
| 124 | | 190 | const atanlo: []const f64 = &.{ |
| 125 | const atanlo = [_]f64{ | 191 | 2.26987774529616870924e-17, // atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 |
| 126 | 2.26987774529616870924e-17, // atan(0.5)lo | 192 | 3.06161699786838301793e-17, // atan(1.0)lo 0x3C81A626, 0x33145C07 |
| 127 | 3.06161699786838301793e-17, // atan(1.0)lo | 193 | 1.39033110312309984516e-17, // atan(1.5)lo 0x3C700788, 0x7AF0CBBD |
| 128 | 1.39033110312309984516e-17, // atan(1.5)lo | 194 | 6.12323399573676603587e-17, // atan(inf)lo 0x3C91A626, 0x33145C07 |
| 129 | 6.12323399573676603587e-17, // atan(inf)lo | | |
| 130 | }; | 195 | }; |
| 131 | | 196 | const aT: []const f64 = &.{ |
| 132 | const aT = [_]f64{ | 197 | 3.33333333333329318027e-01, // 0x3FD55555, 0x5555550D |
| 133 | 3.33333333333329318027e-01, | 198 | -1.99999999998764832476e-01, // 0xBFC99999, 0x9998EBC4 |
| 134 | -1.99999999998764832476e-01, | 199 | 1.42857142725034663711e-01, // 0x3FC24924, 0x920083FF |
| 135 | 1.42857142725034663711e-01, | 200 | -1.11111104054623557880e-01, // 0xBFBC71C6, 0xFE231671 |
| 136 | -1.11111104054623557880e-01, | 201 | 9.09088713343650656196e-02, // 0x3FB745CD, 0xC54C206E |
| 137 | 9.09088713343650656196e-02, | 202 | -7.69187620504482999495e-02, // 0xBFB3B0F2, 0xAF749A6D |
| 138 | -7.69187620504482999495e-02, | 203 | 6.66107313738753120669e-02, // 0x3FB10D66, 0xA0D03D51 |
| 139 | 6.66107313738753120669e-02, | 204 | -5.83357013379057348645e-02, // 0xBFADDE2D, 0x52DEFD9A |
| 140 | -5.83357013379057348645e-02, | 205 | 4.97687799461593236017e-02, // 0x3FA97B4B, 0x24760DEB |
| 141 | 4.97687799461593236017e-02, | 206 | -3.65315727442169155270e-02, // 0xBFA2B444, 0x2C6A6C2F |
| 142 | -3.65315727442169155270e-02, | 207 | 1.62858201153657823623e-02, // 0x3F90AD3A, 0xE322DA11 |
| 143 | 1.62858201153657823623e-02, | | |
| 144 | }; | 208 | }; |
| 145 | | 209 | |
| 146 | var x = x_; | 210 | const hx: u64 = @bitCast(x); |
| 147 | const ux: u64 = @bitCast(x); | 211 | const ix: u32 = @truncate((hx >> 32) & 0x7fffffff); |
| 148 | var ix: u32 = @intCast(ux >> 32); | 212 | const sign = (hx >> 63) != 0; |
| 149 | const sign = ix >> 31; | 213 | // if |x| >= 2^66 |
| 150 | ix &= 0x7FFFFFFF; | | |
| 151 | | | |
| 152 | // |x| >= 2^66 | | |
| 153 | if (ix >= 0x44100000) { | 214 | if (ix >= 0x44100000) { |
| 154 | if (math.isNan(x)) { | 215 | if (math.isNan(x)) { |
| 155 | return x; | 216 | return x; |
| | 217 | } |
| | 218 | const z = atanhi[3] + 0x1p-120; |
| | 219 | return if (sign) -z else z; |
| | 220 | } |
| | 221 | const x_, const id: ?usize = blk: { |
| | 222 | // |x| < 0.4375 |
| | 223 | if (ix < 0x3fdc_0000) { |
| | 224 | // |x| < 2^(-27) |
| | 225 | if (ix < 0x3e40_0000) { |
| | 226 | if (ix < 0x0010_0000) { |
| | 227 | // raise underflow for subnormal x |
| | 228 | mem.doNotOptimizeAway(@as(f32, @floatCast(x))); |
| | 229 | } |
| | 230 | return x; |
| | 231 | } |
| | 232 | break :blk .{ x, null }; |
| 156 | } else { | 233 | } else { |
| 157 | const z = atanhi[3] + 0x1.0p-120; | 234 | const x_ = @abs(x); |
| 158 | return if (sign != 0) -z else z; | 235 | // |x| < 1.1875 |
| | 236 | if (ix < 0x3ff3_0000) { |
| | 237 | // 7/16 <= |x| < 11/16 |
| | 238 | if (ix < 0x3fe6_0000) { |
| | 239 | break :blk .{ (2.0 * x_ - 1.0) / (2.0 + x_), 0 }; |
| | 240 | } |
| | 241 | // 11/16 <= |x| < 19/16 |
| | 242 | else { |
| | 243 | break :blk .{ (x_ - 1.0) / (x_ + 1.0), 1 }; |
| | 244 | } |
| | 245 | } else { |
| | 246 | // |x| < 2.4375 |
| | 247 | if (ix < 0x4003_8000) { |
| | 248 | break :blk .{ (x_ - 1.5) / (1.0 + 1.5 * x_), 2 }; |
| | 249 | } |
| | 250 | // 2.4375 <= |x| < 2^66 |
| | 251 | else { |
| | 252 | break :blk .{ -1.0 / x_, 3 }; |
| | 253 | } |
| | 254 | } |
| 159 | } | 255 | } |
| | 256 | }; |
| | 257 | // end of argument reduction |
| | 258 | const z = x_ * x_; |
| | 259 | const w = z * z; |
| | 260 | // break sum from i=0 to 10 aT[i]z^(i+1) into odd and even poly |
| | 261 | const s1 = z * (aT[0] + w * (aT[2] + w * (aT[4] + w * (aT[6] + w * (aT[8] + w * aT[10]))))); |
| | 262 | const s2 = w * (aT[1] + w * (aT[3] + w * (aT[5] + w * (aT[7] + w * aT[9])))); |
| | 263 | if (id) |id_| { |
| | 264 | const z_ = atanhi[id_] - (x_ * (s1 + s2) - atanlo[id_] - x_); |
| | 265 | return if (sign) -z_ else z_; |
| | 266 | } else { |
| | 267 | return x_ - x_ * (s1 + s2); |
| 160 | } | 268 | } |
| | 269 | } |
| 161 | | 270 | |
| 162 | var id: ?usize = undefined; | 271 | fn atanExtended80(x: f80) f80 { |
| | 272 | const atanhi: []const f80 = &.{ |
| | 273 | 4.63647609000806116202e-01, |
| | 274 | 7.85398163397448309628e-01, |
| | 275 | 9.82793723247329067960e-01, |
| | 276 | 1.57079632679489661926e+00, |
| | 277 | }; |
| | 278 | const atanlo: []const f80 = &.{ |
| | 279 | 1.18469937025062860669e-20, |
| | 280 | -1.25413940316708300586e-20, |
| | 281 | 2.55232234165405176172e-20, |
| | 282 | -2.50827880633416601173e-20, |
| | 283 | }; |
| | 284 | const aT: []const f80 = &.{ |
| | 285 | 3.33333333333333333017e-01, |
| | 286 | -1.99999999999999632011e-01, |
| | 287 | 1.42857142857046531280e-01, |
| | 288 | -1.11111111100562372733e-01, |
| | 289 | 9.09090902935647302252e-02, |
| | 290 | -7.69230552476207730353e-02, |
| | 291 | 6.66661718042406260546e-02, |
| | 292 | -5.88158892835030888692e-02, |
| | 293 | 5.25499891539726639379e-02, |
| | 294 | -4.70119845393155721494e-02, |
| | 295 | 4.03539201366454414072e-02, |
| | 296 | -2.91303858419364158725e-02, |
| | 297 | 1.24822046299269234080e-02, |
| | 298 | }; |
| 163 | | 299 | |
| 164 | // |x| < 0.4375 | 300 | const hx: u80 = @bitCast(x); |
| 165 | if (ix < 0x3FDC0000) { | 301 | const se: u16 = @truncate(hx >> 64); |
| 166 | // |x| < 2^(-27) | 302 | const e = se & 0x7fff; |
| 167 | if (ix < 0x3E400000) { | 303 | const sign = se >> 15 != 0; |
| 168 | if (ix < 0x00100000) { | 304 | // if |x| is large, atan(x)~=pi/2 |
| 169 | mem.doNotOptimizeAway(@as(f32, @floatCast(x))); | 305 | if (e >= 0x3fff + math.floatMantissaBits(f80) + 1) { |
| 170 | } | 306 | if (math.isNan(x)) { |
| 171 | return x; | 307 | return x; |
| 172 | } | 308 | } |
| 173 | id = null; | 309 | return if (sign) -atanhi[3] else atanhi[3]; |
| 174 | } else { | 310 | } |
| 175 | x = @abs(x); | 311 | // Extract the exponent and the first few bits of the mantissa. |
| 176 | // |x| < 1.1875 | 312 | const m: u64 = @truncate(hx & 0x0000_ffff_ffff_ffff_ffff); |
| 177 | if (ix < 0x3FF30000) { | 313 | const expman = ((@as(u32, @intCast(se)) & 0x7fff) << 8) | (@as(u32, @truncate(m >> 55)) & 0xff); |
| 178 | // 7/16 <= |x| < 11/16 | 314 | const x_, const id: ?usize = blk: { |
| 179 | if (ix < 0x3FE60000) { | 315 | // |x| < 0.4375 |
| 180 | id = 0; | 316 | if (expman < ((0x3fff - 2) << 8) + 0xc0) { |
| 181 | x = (2.0 * x - 1.0) / (2.0 + x); | 317 | // if |x| is small, atanl(x)~=x |
| 182 | } | 318 | if (e < 0x3fff - (math.floatMantissaBits(f80) + 1) / 2) { |
| 183 | // 11/16 <= |x| < 19/16 | 319 | // raise underflow if subnormal |
| 184 | else { | 320 | if (e == 0) { |
| 185 | id = 1; | 321 | std.mem.doNotOptimizeAway(@as(f32, @floatCast(x))); |
| 186 | x = (x - 1.0) / (x + 1.0); | 322 | } |
| | 323 | return x; |
| 187 | } | 324 | } |
| | 325 | break :blk .{ x, null }; |
| 188 | } else { | 326 | } else { |
| 189 | // |x| < 2.4375 | 327 | const x_ = @abs(x); |
| 190 | if (ix < 0x40038000) { | 328 | // |x| < 1.1875 |
| 191 | id = 2; | 329 | if (expman < (0x3fff << 8) + 0x30) { |
| 192 | x = (x - 1.5) / (1.0 + 1.5 * x); | 330 | // 7/16 <= |x| < 11/16 |
| 193 | } | 331 | if (expman < ((0x3fff - 1) << 8) + 0x60) { |
| 194 | // 2.4375 <= |x| < 2^66 | 332 | break :blk .{ (2.0 * x_ - 1.0) / (2.0 + x_), 0 }; |
| 195 | else { | 333 | } |
| 196 | id = 3; | 334 | // 11/16 <= |x| < 19/16 |
| 197 | x = -1.0 / x; | 335 | else { |
| | 336 | break :blk .{ (x_ - 1.0) / (x_ + 1.0), 1 }; |
| | 337 | } |
| | 338 | } else { |
| | 339 | // |x| < 2.4375 |
| | 340 | if (expman < ((0x3fff + 1) << 8) + 0x38) { |
| | 341 | break :blk .{ (x_ - 1.5) / (1.0 + 1.5 * x_), 2 }; |
| | 342 | } |
| | 343 | // 2.4375 <= |x| |
| | 344 | else { |
| | 345 | break :blk .{ -1.0 / x_, 3 }; |
| | 346 | } |
| 198 | } | 347 | } |
| 199 | } | 348 | } |
| | 349 | }; |
| | 350 | // end of argument reduction |
| | 351 | const z = x_ * x_; |
| | 352 | const w = z * z; |
| | 353 | // break sum aT[i]z^(i+1) into odd and even poly |
| | 354 | const s1 = z * (aT[0] + w * (aT[2] + w * (aT[4] + w * (aT[6] + w * (aT[8] + w * (aT[10] + w * aT[12])))))); |
| | 355 | const s2 = w * (aT[1] + w * (aT[3] + w * (aT[5] + w * (aT[7] + w * (aT[9] + w * aT[11]))))); |
| | 356 | if (id) |id_| { |
| | 357 | const z_ = atanhi[id_] - ((x_ * (s1 + s2) - atanlo[id_]) - x_); |
| | 358 | return if (sign) -z_ else z_; |
| | 359 | } else { |
| | 360 | return x_ - x_ * (s1 + s2); |
| 200 | } | 361 | } |
| | 362 | } |
| 201 | | 363 | |
| 202 | const z = x * x; | 364 | fn atanBinary128(x: f128) f128 { |
| 203 | const w = z * z; | 365 | const atanhi: []const f128 = &.{ |
| 204 | const s1 = z * (aT[0] + w * (aT[2] + w * (aT[4] + w * (aT[6] + w * (aT[8] + w * aT[10]))))); | 366 | 4.63647609000806116214256231461214397e-01, |
| 205 | const s2 = w * (aT[1] + w * (aT[3] + w * (aT[5] + w * (aT[7] + w * aT[9])))); | 367 | 7.85398163397448309615660845819875699e-01, |
| | 368 | 9.82793723247329067985710611014666038e-01, |
| | 369 | 1.57079632679489661923132169163975140e+00, |
| | 370 | }; |
| | 371 | const atanlo: []const f128 = &.{ |
| | 372 | 4.89509642257333492668618435220297706e-36, |
| | 373 | 2.16795253253094525619926100651083806e-35, |
| | 374 | -2.31288434538183565909319952098066272e-35, |
| | 375 | 4.33590506506189051239852201302167613e-35, |
| | 376 | }; |
| | 377 | const aT: []const f128 = &.{ |
| | 378 | 3.33333333333333333333333333333333125e-01, |
| | 379 | -1.99999999999999999999999999999180430e-01, |
| | 380 | 1.42857142857142857142857142125269827e-01, |
| | 381 | -1.11111111111111111111110834490810169e-01, |
| | 382 | 9.09090909090909090908522355708623681e-02, |
| | 383 | -7.69230769230769230696553844935357021e-02, |
| | 384 | 6.66666666666666660390096773046256096e-02, |
| | 385 | -5.88235294117646671706582985209643694e-02, |
| | 386 | 5.26315789473666478515847092020327506e-02, |
| | 387 | -4.76190476189855517021024424991436144e-02, |
| | 388 | 4.34782608678695085948531993458097026e-02, |
| | 389 | -3.99999999632663469330634215991142368e-02, |
| | 390 | 3.70370363987423702891250829918659723e-02, |
| | 391 | -3.44827496515048090726669907612335954e-02, |
| | 392 | 3.22579620681420149871973710852268528e-02, |
| | 393 | -3.03020767654269261041647570626778067e-02, |
| | 394 | 2.85641979882534783223403715930946138e-02, |
| | 395 | -2.69824879726738568189929461383741323e-02, |
| | 396 | 2.54194698498808542954187110873675769e-02, |
| | 397 | -2.35083879708189059926183138130183215e-02, |
| | 398 | 2.04832358998165364349957325067131428e-02, |
| | 399 | -1.54489555488544397858507248612362957e-02, |
| | 400 | 8.64492360989278761493037861575248038e-03, |
| | 401 | -2.58521121597609872727919154569765469e-03, |
| | 402 | }; |
| 206 | | 403 | |
| 207 | if (id) |id_value| { | 404 | const hx: u128 = @bitCast(x); |
| 208 | const zz = atanhi[id_value] - ((x * (s1 + s2) - atanlo[id_value]) - x); | 405 | const se: u16 = @truncate(hx >> 112); |
| 209 | return if (sign != 0) -zz else zz; | 406 | const e = se & 0x7fff; |
| | 407 | const sign = se >> 15 != 0; |
| | 408 | // if |x| is large, atan(x)~=pi/2 |
| | 409 | if (e >= 0x3fff + math.floatMantissaBits(f128) + 2) { |
| | 410 | if (math.isNan(x)) { |
| | 411 | return x; |
| | 412 | } |
| | 413 | return if (sign) -atanhi[3] else atanhi[3]; |
| | 414 | } |
| | 415 | // Extract the exponent and the first few bits of the mantissa. |
| | 416 | const top: u16 = @truncate((hx >> 96) & 0x0000_ffff); |
| | 417 | const expman = ((@as(u32, @intCast(se)) & 0x7fff) << 8) | (@as(u32, @intCast(top)) >> 8); |
| | 418 | const x_, const id: ?usize = blk: { |
| | 419 | // |x| < 0.4375 |
| | 420 | if (expman < ((0x3fff - 2) << 8) + 0xc0) { |
| | 421 | // if |x| is small, atanl(x)~=x |
| | 422 | if (e < 0x3fff - (math.floatMantissaBits(f128) + 2) / 2) { |
| | 423 | // raise underflow if subnormal |
| | 424 | if (e == 0) { |
| | 425 | mem.doNotOptimizeAway(@as(f32, @floatCast(x))); |
| | 426 | } |
| | 427 | return x; |
| | 428 | } |
| | 429 | break :blk .{ x, null }; |
| | 430 | } else { |
| | 431 | const x_ = @abs(x); |
| | 432 | // |x| < 1.1875 |
| | 433 | if (expman < (0x3fff << 8) + 0x30) { |
| | 434 | // 7/16 <= |x| < 11/16 |
| | 435 | if (expman < ((0x3fff - 1) << 8) + 0x60) { |
| | 436 | break :blk .{ (2.0 * x_ - 1.0) / (2.0 + x_), 0 }; |
| | 437 | } |
| | 438 | // 11/16 <= |x| < 19/16 |
| | 439 | else { |
| | 440 | break :blk .{ (x_ - 1.0) / (x_ + 1.0), 1 }; |
| | 441 | } |
| | 442 | } else { |
| | 443 | // |x| < 2.4375 |
| | 444 | if (expman < ((0x3fff + 1) << 8) + 0x38) { |
| | 445 | break :blk .{ (x_ - 1.5) / (1.0 + 1.5 * x_), 2 }; |
| | 446 | } |
| | 447 | // 2.4375 <= |x| |
| | 448 | else { |
| | 449 | break :blk .{ -1.0 / x_, 3 }; |
| | 450 | } |
| | 451 | } |
| | 452 | } |
| | 453 | }; |
| | 454 | // end of argument reduction |
| | 455 | const z = x_ * x_; |
| | 456 | const w = z * z; |
| | 457 | // break sum aT[i]z^(i+1) into odd and even poly |
| | 458 | const s1 = z * (aT[0] + w * (aT[2] + w * (aT[4] + w * (aT[6] + w * (aT[8] + w * (aT[10] + w * (aT[12] + w * (aT[14] + w * (aT[16] + w * (aT[18] + w * (aT[20] + w * aT[22]))))))))))); |
| | 459 | const s2 = w * (aT[1] + w * (aT[3] + w * (aT[5] + w * (aT[7] + w * (aT[9] + w * (aT[11] + w * (aT[13] + w * (aT[15] + w * (aT[17] + w * (aT[19] + w * (aT[21] + w * aT[23]))))))))))); |
| | 460 | if (id) |id_| { |
| | 461 | const z_ = atanhi[id_] - ((x_ * (s1 + s2) - atanlo[id_]) - x_); |
| | 462 | return if (sign) -z_ else z_; |
| 210 | } else { | 463 | } else { |
| 211 | return x - x * (s1 + s2); | 464 | return x_ - x_ * (s1 + s2); |
| 212 | } | 465 | } |
| 213 | } | 466 | } |
| 214 | | 467 | |
| 215 | test atan { | 468 | test "atanBinary16.special" { |
| 216 | try expect(@as(u32, @bitCast(atan(@as(f32, 0.2)))) == @as(u32, @bitCast(atan32(0.2)))); | 469 | try testing.expectEqual(atanBinary16(0x0p+0), 0x0p+0); |
| 217 | try expect(atan(@as(f64, 0.2)) == atan64(0.2)); | 470 | try testing.expectEqual(atanBinary16(-0x0p+0), -0x0p+0); |
| | 471 | try testing.expectApproxEqAbs(atanBinary16(0x1p+0), 0x1.92p-1, math.floatEpsAt(f16, 0x1.92p-1)); |
| | 472 | try testing.expectApproxEqAbs(atanBinary16(-0x1p+0), -0x1.92p-1, math.floatEpsAt(f16, -0x1.92p-1)); |
| | 473 | try testing.expectApproxEqAbs(atanBinary16(math.inf(f16)), 0x1.92p0, math.floatEpsAt(f16, 0x1.92p0)); |
| | 474 | try testing.expectApproxEqAbs(atanBinary16(-math.inf(f16)), -0x1.92p0, math.floatEpsAt(f16, -0x1.92p0)); |
| | 475 | try testing.expect(math.isNan(atanBinary16(math.nan(f16)))); |
| 218 | } | 476 | } |
| 219 | | 477 | |
| 220 | test atan32 { | 478 | test "atanBinary16" { |
| 221 | const epsilon = 0.000001; | 479 | try testing.expectApproxEqAbs(atanBinary16(-0x1.864p-2), -0x1.74cp-2, math.floatEpsAt(f16, -0x1.74cp-2)); |
| | 480 | try testing.expectApproxEqAbs(atanBinary16(-0x1.59cp1), -0x1.374p0, math.floatEpsAt(f16, -0x1.374p0)); |
| | 481 | try testing.expectApproxEqAbs(atanBinary16(-0x1.d2cp0), -0x1.11cp0, math.floatEpsAt(f16, -0x1.11cp0)); |
| | 482 | try testing.expectApproxEqAbs(atanBinary16(-0x1.5f4p-1), -0x1.33cp-1, math.floatEpsAt(f16, -0x1.33cp-1)); |
| | 483 | try testing.expectApproxEqAbs(atanBinary16(0x1.588p1), 0x1.37p0, math.floatEpsAt(f16, 0x1.37p0)); |
| | 484 | try testing.expectApproxEqAbs(atanBinary16(-0x1.b14p-2), -0x1.99cp-2, math.floatEpsAt(f16, -0x1.99cp-2)); |
| | 485 | try testing.expectApproxEqAbs(atanBinary16(0x1.3ccp1), 0x1.2fcp0, math.floatEpsAt(f16, 0x1.2fcp0)); |
| | 486 | try testing.expectApproxEqAbs(atanBinary16(-0x1.0ecp-2), -0x1.08cp-2, math.floatEpsAt(f16, -0x1.08cp-2)); |
| | 487 | try testing.expectApproxEqAbs(atanBinary16(0x1.298p1), 0x1.2ap0, math.floatEpsAt(f16, 0x1.2ap0)); |
| | 488 | try testing.expectApproxEqAbs(atanBinary16(-0x1.028p1), -0x1.1c8p0, math.floatEpsAt(f16, -0x1.1c8p0)); |
| | 489 | } |
| 222 | | 490 | |
| 223 | try expect(math.approxEqAbs(f32, atan32(0.2), 0.197396, epsilon)); | 491 | test "atanBinary32.special" { |
| 224 | try expect(math.approxEqAbs(f32, atan32(-0.2), -0.197396, epsilon)); | 492 | try testing.expectEqual(atanBinary32(0x0p+0), 0x0p+0); |
| 225 | try expect(math.approxEqAbs(f32, atan32(0.3434), 0.330783, epsilon)); | 493 | try testing.expectEqual(atanBinary32(-0x0p+0), -0x0p+0); |
| 226 | try expect(math.approxEqAbs(f32, atan32(0.8923), 0.728545, epsilon)); | 494 | try testing.expectApproxEqAbs(atanBinary32(0x1p+0), 0x1.921fb6p-1, math.floatEpsAt(f32, 0x1.921fb6p-1)); |
| 227 | try expect(math.approxEqAbs(f32, atan32(1.5), 0.982794, epsilon)); | 495 | try testing.expectApproxEqAbs(atanBinary32(-0x1p+0), -0x1.921fb6p-1, math.floatEpsAt(f32, -0x1.921fb6p-1)); |
| | 496 | try testing.expectApproxEqAbs(atanBinary32(math.inf(f32)), 0x1.921fb6p+0, math.floatEpsAt(f32, 0x1.921fb6p+0)); |
| | 497 | try testing.expectApproxEqAbs(atanBinary32(-math.inf(f32)), -0x1.921fb6p+0, math.floatEpsAt(f32, -0x1.921fb6p+0)); |
| | 498 | try testing.expect(math.isNan(atanBinary32(math.nan(f32)))); |
| 228 | } | 499 | } |
| 229 | | 500 | |
| 230 | test atan64 { | 501 | test "atanBinary32" { |
| 231 | const epsilon = 0.000001; | 502 | try testing.expectApproxEqAbs(atanBinary32(-0x1.8629dp-2), -0x1.74c62p-2, math.floatEpsAt(f32, -0x1.74c62p-2)); |
| | 503 | try testing.expectApproxEqAbs(atanBinary32(-0x1.59d42ep1), -0x1.375fd8p0, math.floatEpsAt(f32, -0x1.375fd8p0)); |
| | 504 | try testing.expectApproxEqAbs(atanBinary32(-0x1.d2dbe2p0), -0x1.11b8aep0, math.floatEpsAt(f32, -0x1.11b8aep0)); |
| | 505 | try testing.expectApproxEqAbs(atanBinary32(-0x1.5f314ep-1), -0x1.33d28cp-1, math.floatEpsAt(f32, -0x1.33d28cp-1)); |
| | 506 | try testing.expectApproxEqAbs(atanBinary32(0x1.5869bp1), 0x1.37082ep0, math.floatEpsAt(f32, 0x1.37082ep0)); |
| | 507 | try testing.expectApproxEqAbs(atanBinary32(-0x1.b13a06p-2), -0x1.99d7cap-2, math.floatEpsAt(f32, -0x1.99d7cap-2)); |
| | 508 | try testing.expectApproxEqAbs(atanBinary32(0x1.3cb0f2p1), 0x1.2fcb12p0, math.floatEpsAt(f32, 0x1.2fcb12p0)); |
| | 509 | try testing.expectApproxEqAbs(atanBinary32(-0x1.0ed746p-2), -0x1.08c71ap-2, math.floatEpsAt(f32, -0x1.08c71ap-2)); |
| | 510 | try testing.expectApproxEqAbs(atanBinary32(0x1.299d54p1), 0x1.2a24e2p0, math.floatEpsAt(f32, 0x1.2a24e2p0)); |
| | 511 | try testing.expectApproxEqAbs(atanBinary32(-0x1.0264fcp1), -0x1.1c6178p0, math.floatEpsAt(f32, -0x1.1c6178p0)); |
| | 512 | } |
| 232 | | 513 | |
| 233 | try expect(math.approxEqAbs(f64, atan64(0.2), 0.197396, epsilon)); | 514 | test "atanBinary64.special" { |
| 234 | try expect(math.approxEqAbs(f64, atan64(-0.2), -0.197396, epsilon)); | 515 | try testing.expectEqual(atanBinary64(0x0p+0), 0x0p+0); |
| 235 | try expect(math.approxEqAbs(f64, atan64(0.3434), 0.330783, epsilon)); | 516 | try testing.expectEqual(atanBinary64(-0x0p+0), -0x0p+0); |
| 236 | try expect(math.approxEqAbs(f64, atan64(0.8923), 0.728545, epsilon)); | 517 | try testing.expectApproxEqAbs(atanBinary64(0x1p+0), 0x1.921fb54442d18p-1, math.floatEpsAt(f64, 0x1.921fb54442d18p-1)); |
| 237 | try expect(math.approxEqAbs(f64, atan64(1.5), 0.982794, epsilon)); | 518 | try testing.expectApproxEqAbs(atanBinary64(-0x1p+0), -0x1.921fb54442d18p-1, math.floatEpsAt(f64, -0x1.921fb54442d18p-1)); |
| | 519 | try testing.expectApproxEqAbs(atanBinary64(math.inf(f64)), 0x1.921fb54442d18p+0, math.floatEpsAt(f64, 0x1.921fb54442d18p+0)); |
| | 520 | try testing.expectApproxEqAbs(atanBinary64(-math.inf(f64)), -0x1.921fb54442d18p+0, math.floatEpsAt(f64, -0x1.921fb54442d18p+0)); |
| | 521 | try testing.expect(math.isNan(atanBinary64(math.nan(f64)))); |
| 238 | } | 522 | } |
| 239 | | 523 | |
| 240 | test "atan32.special" { | 524 | test "atanBinary64" { |
| 241 | const epsilon = 0.000001; | 525 | try testing.expectApproxEqAbs(atanBinary64(-0x1.8629d0244cdccp-2), -0x1.74c61f4377016p-2, math.floatEpsAt(f64, -0x1.74c61f4377016p-2)); |
| | 526 | try testing.expectApproxEqAbs(atanBinary64(-0x1.59d42d4659937p1), -0x1.375fd7987cc2p0, math.floatEpsAt(f64, -0x1.375fd7987cc2p0)); |
| | 527 | try testing.expectApproxEqAbs(atanBinary64(-0x1.d2dbe23d04f06p0), -0x1.11b8adeba5616p0, math.floatEpsAt(f64, -0x1.11b8adeba5616p0)); |
| | 528 | try testing.expectApproxEqAbs(atanBinary64(-0x1.5f314e72398e8p-1), -0x1.33d28ca762539p-1, math.floatEpsAt(f64, -0x1.33d28ca762539p-1)); |
| | 529 | try testing.expectApproxEqAbs(atanBinary64(0x1.5869af37b7d08p1), 0x1.37082ce2dd03p0, math.floatEpsAt(f64, 0x1.37082ce2dd03p0)); |
| | 530 | try testing.expectApproxEqAbs(atanBinary64(-0x1.b13a05a662618p-2), -0x1.99d7cac66dd44p-2, math.floatEpsAt(f64, -0x1.99d7cac66dd44p-2)); |
| | 531 | try testing.expectApproxEqAbs(atanBinary64(0x1.3cb0f12f39d8ap1), 0x1.2fcb120468e8ep0, math.floatEpsAt(f64, 0x1.2fcb120468e8ep0)); |
| | 532 | try testing.expectApproxEqAbs(atanBinary64(-0x1.0ed746b39cbb7p-2), -0x1.08c71aa0e509p-2, math.floatEpsAt(f64, -0x1.08c71aa0e509p-2)); |
| | 533 | try testing.expectApproxEqAbs(atanBinary64(0x1.299d54ac7d6bp1), 0x1.2a24e22d861dfp0, math.floatEpsAt(f64, 0x1.2a24e22d861dfp0)); |
| | 534 | try testing.expectApproxEqAbs(atanBinary64(-0x1.0264fb9f3d50ep1), -0x1.1c617825f9751p0, math.floatEpsAt(f64, -0x1.1c617825f9751p0)); |
| | 535 | } |
| | 536 | |
| | 537 | test "atanExtended80.special" { |
| | 538 | try testing.expectEqual(atanExtended80(0x0p+0), 0x0p+0); |
| | 539 | try testing.expectEqual(atanExtended80(-0x0p+0), -0x0p+0); |
| | 540 | try testing.expectApproxEqAbs(atanExtended80(0x1p+0), 0x1.921fb54442d1846ap-1, math.floatEpsAt(f80, 0x1.921fb54442d1846ap-1)); |
| | 541 | try testing.expectApproxEqAbs(atanExtended80(-0x1p+0), -0x1.921fb54442d1846ap-1, math.floatEpsAt(f80, -0x1.921fb54442d1846ap-1)); |
| | 542 | try testing.expectApproxEqAbs(atanExtended80(math.inf(f80)), 0x1.921fb54442d1846ap0, math.floatEpsAt(f80, 0x1.921fb54442d1846ap0)); |
| | 543 | try testing.expectApproxEqAbs(atanExtended80(-math.inf(f80)), -0x1.921fb54442d1846ap0, math.floatEpsAt(f80, -0x1.921fb54442d1846ap0)); |
| | 544 | try testing.expect(math.isNan(atanExtended80(math.nan(f80)))); |
| | 545 | } |
| 242 | | 546 | |
| 243 | try expect(math.isPositiveZero(atan32(0.0))); | 547 | test "atanExtended80" { |
| 244 | try expect(math.isNegativeZero(atan32(-0.0))); | 548 | try testing.expectApproxEqAbs(atanExtended80(-0x1.8629d0244cdcbed8p-2), -0x1.74c61f437701661p-2, math.floatEpsAt(f80, -0x1.74c61f437701661p-2)); |
| 245 | try expect(math.approxEqAbs(f32, atan32(math.inf(f32)), math.pi / 2.0, epsilon)); | 549 | try testing.expectApproxEqAbs(atanExtended80(-0x1.59d42d4659936d9ep1), -0x1.375fd7987cc1fd02p0, math.floatEpsAt(f80, -0x1.375fd7987cc1fd02p0)); |
| 246 | try expect(math.approxEqAbs(f32, atan32(-math.inf(f32)), -math.pi / 2.0, epsilon)); | 550 | try testing.expectApproxEqAbs(atanExtended80(-0x1.d2dbe23d04f067b4p0), -0x1.11b8adeba5615e04p0, math.floatEpsAt(f80, -0x1.11b8adeba5615e04p0)); |
| | 551 | try testing.expectApproxEqAbs(atanExtended80(-0x1.5f314e72398e7dbcp-1), -0x1.33d28ca76253964cp-1, math.floatEpsAt(f80, -0x1.33d28ca76253964cp-1)); |
| | 552 | try testing.expectApproxEqAbs(atanExtended80(0x1.5869af37b7d078cap1), 0x1.37082ce2dd03010cp0, math.floatEpsAt(f80, 0x1.37082ce2dd03010cp0)); |
| | 553 | try testing.expectApproxEqAbs(atanExtended80(-0x1.b13a05a66261821ap-2), -0x1.99d7cac66dd4438p-2, math.floatEpsAt(f80, -0x1.99d7cac66dd4438p-2)); |
| | 554 | try testing.expectApproxEqAbs(atanExtended80(0x1.3cb0f12f39d899cp1), 0x1.2fcb120468e8d9ecp0, math.floatEpsAt(f80, 0x1.2fcb120468e8d9ecp0)); |
| | 555 | try testing.expectApproxEqAbs(atanExtended80(-0x1.0ed746b39cbb7614p-2), -0x1.08c71aa0e5090998p-2, math.floatEpsAt(f80, -0x1.08c71aa0e5090998p-2)); |
| | 556 | try testing.expectApproxEqAbs(atanExtended80(0x1.299d54ac7d6afc52p1), 0x1.2a24e22d861debfep0, math.floatEpsAt(f80, 0x1.2a24e22d861debfep0)); |
| | 557 | try testing.expectApproxEqAbs(atanExtended80(-0x1.0264fb9f3d50e4fp1), -0x1.1c617825f97512b8p0, math.floatEpsAt(f80, -0x1.1c617825f97512b8p0)); |
| 247 | } | 558 | } |
| 248 | | 559 | |
| 249 | test "atan64.special" { | 560 | test "atanBinary128.special" { |
| 250 | const epsilon = 0.000001; | 561 | try testing.expectEqual(atanBinary128(0x0p+0), 0x0p+0); |
| | 562 | try testing.expectEqual(atanBinary128(-0x0p+0), -0x0p+0); |
| | 563 | try testing.expectApproxEqAbs(atanBinary128(0x1p+0), 0x1.921fb54442d18469898cc51701b8p-1, math.floatEpsAt(f128, 0x1.921fb54442d18469898cc51701b8p-1)); |
| | 564 | try testing.expectApproxEqAbs(atanBinary128(-0x1p+0), -0x1.921fb54442d18469898cc51701b8p-1, math.floatEpsAt(f128, -0x1.921fb54442d18469898cc51701b8p-1)); |
| | 565 | try testing.expectApproxEqAbs(atanBinary128(math.inf(f128)), 0x1.921fb54442d18469898cc51701b8p0, math.floatEpsAt(f128, 0x1.921fb54442d18469898cc51701b8p0)); |
| | 566 | try testing.expectApproxEqAbs(atanBinary128(-math.inf(f128)), -0x1.921fb54442d18469898cc51701b8p0, math.floatEpsAt(f128, -0x1.921fb54442d18469898cc51701b8p0)); |
| | 567 | try testing.expect(math.isNan(atanBinary128(math.nan(f128)))); |
| | 568 | } |
| 251 | | 569 | |
| 252 | try expect(math.isPositiveZero(atan64(0.0))); | 570 | test "atanBinary128" { |
| 253 | try expect(math.isNegativeZero(atan64(-0.0))); | 571 | try testing.expectApproxEqAbs(atanBinary128(-0x1.8629d0244cdcbed71792ccdec26dp-2), -0x1.74c61f437701660ff76989d23707p-2, math.floatEpsAt(f128, -0x1.74c61f437701660ff76989d23707p-2)); |
| 254 | try expect(math.approxEqAbs(f64, atan64(math.inf(f64)), math.pi / 2.0, epsilon)); | 572 | try testing.expectApproxEqAbs(atanBinary128(-0x1.59d42d4659936d9e22b5dea4faefp1), -0x1.375fd7987cc1fd0119cf0cc5b708p0, math.floatEpsAt(f128, -0x1.375fd7987cc1fd0119cf0cc5b708p0)); |
| 255 | try expect(math.approxEqAbs(f64, atan64(-math.inf(f64)), -math.pi / 2.0, epsilon)); | 573 | try testing.expectApproxEqAbs(atanBinary128(-0x1.d2dbe23d04f067b42da3f8efdf57p0), -0x1.11b8adeba5615e0370722b511231p0, math.floatEpsAt(f128, -0x1.11b8adeba5615e0370722b511231p0)); |
| | 574 | try testing.expectApproxEqAbs(atanBinary128(-0x1.5f314e72398e7dbbe70fb072983ep-1), -0x1.33d28ca76253964cb5d3581cdd88p-1, math.floatEpsAt(f128, -0x1.33d28ca76253964cb5d3581cdd88p-1)); |
| | 575 | try testing.expectApproxEqAbs(atanBinary128(0x1.5869af37b7d078caa3456c44aecep1), 0x1.37082ce2dd03010bbea814dc5882p0, math.floatEpsAt(f128, 0x1.37082ce2dd03010bbea814dc5882p0)); |
| | 576 | try testing.expectApproxEqAbs(atanBinary128(-0x1.b13a05a66261821a364ad8c6c999p-2), -0x1.99d7cac66dd4438077284b491a91p-2, math.floatEpsAt(f128, -0x1.99d7cac66dd4438077284b491a91p-2)); |
| | 577 | try testing.expectApproxEqAbs(atanBinary128(0x1.3cb0f12f39d899c0d963ac413297p1), 0x1.2fcb120468e8d9ebdb74702314c8p0, math.floatEpsAt(f128, 0x1.2fcb120468e8d9ebdb74702314c8p0)); |
| | 578 | try testing.expectApproxEqAbs(atanBinary128(-0x1.0ed746b39cbb7614d8735e8315a8p-2), -0x1.08c71aa0e5090998206fbbe2090fp-2, math.floatEpsAt(f128, -0x1.08c71aa0e5090998206fbbe2090fp-2)); |
| | 579 | try testing.expectApproxEqAbs(atanBinary128(0x1.299d54ac7d6afc5154643b601519p1), 0x1.2a24e22d861debfd6f974500567fp0, math.floatEpsAt(f128, 0x1.2a24e22d861debfd6f974500567fp0)); |
| | 580 | try testing.expectApproxEqAbs(atanBinary128(-0x1.0264fb9f3d50e4f0f966f0686064p1), -0x1.1c617825f97512b7f38656ab12cdp0, math.floatEpsAt(f128, -0x1.1c617825f97512b7f38656ab12cdp0)); |
| 256 | } | 581 | } |