@@ -10,6 +10,7 @@ const std = @import("../std.zig");
10
10
const math = std .math ;
11
11
const mem = std .mem ;
12
12
const expect = std .testing .expect ;
13
+ const expectEqual = std .testing .expectEqual ;
13
14
14
15
/// Returns e raised to the power of x, minus 1 (e^x - 1). This is more accurate than exp(e, x) - 1
15
16
/// when x is near 0.
@@ -39,9 +40,9 @@ fn expm1_32(x_: f32) f32 {
39
40
const Q2 : f32 = 1.5807170421e-3 ;
40
41
41
42
var x = x_ ;
42
- const ux = @as ( u32 , @ bitCast (x ) );
43
+ const ux : u32 = @bitCast (x );
43
44
const hx = ux & 0x7FFFFFFF ;
44
- const sign = hx >> 31 ;
45
+ const sign = ux >> 31 ;
45
46
46
47
// TODO: Shouldn't need this check explicitly.
47
48
if (math .isNegativeInf (x )) {
@@ -147,7 +148,7 @@ fn expm1_32(x_: f32) f32 {
147
148
return y - 1.0 ;
148
149
}
149
150
150
- const uf = @as ( f32 , @ bitCast (@as (u32 , @intCast (0x7F -% k )) << 23 ) );
151
+ const uf : f32 = @bitCast (@as (u32 , @intCast (0x7F -% k )) << 23 );
151
152
if (k < 23 ) {
152
153
return (x - e + (1 - uf )) * twopk ;
153
154
} else {
@@ -286,39 +287,77 @@ fn expm1_64(x_: f64) f64 {
286
287
}
287
288
}
288
289
289
- test expm1 {
290
- try expect (expm1 (@as (f32 , 0.0 )) == expm1_32 (0.0 ));
291
- try expect (expm1 (@as (f64 , 0.0 )) == expm1_64 (0.0 ));
290
+ test "expm1_32() special" {
291
+ try expectEqual (expm1_32 (0.0 ), 0.0 );
292
+ try expectEqual (expm1_32 (-0.0 ), 0.0 );
293
+ try expectEqual (expm1_32 (math .ln2 ), 1.0 );
294
+ try expectEqual (expm1_32 (math .inf (f32 )), math .inf (f32 ));
295
+ try expectEqual (expm1_32 (- math .inf (f32 )), -1.0 );
296
+ try expect (math .isNan (expm1_32 (math .nan (f32 ))));
297
+ try expect (math .isNan (expm1_32 (math .snan (f32 ))));
292
298
}
293
299
294
- test expm1_32 {
295
- const epsilon = 0.000001 ;
296
-
297
- try expect (math .isPositiveZero (expm1_32 (0.0 )));
298
- try expect (math .approxEqAbs (f32 , expm1_32 (0.0 ), 0.0 , epsilon ));
299
- try expect (math .approxEqAbs (f32 , expm1_32 (0.2 ), 0.221403 , epsilon ));
300
- try expect (math .approxEqAbs (f32 , expm1_32 (0.8923 ), 1.440737 , epsilon ));
301
- try expect (math .approxEqAbs (f32 , expm1_32 (1.5 ), 3.481689 , epsilon ));
300
+ test "expm1_32() sanity" {
301
+ try expectEqual (expm1_32 (-0x1.0223a0p+3 ), -0x1.ffd6e0p-1 );
302
+ try expectEqual (expm1_32 (0x1.161868p+2 ), 0x1.30712ap+6 );
303
+ try expectEqual (expm1_32 (-0x1.0c34b4p+3 ), -0x1.ffe1fap-1 );
304
+ try expectEqual (expm1_32 (-0x1.a206f0p+2 ), -0x1.ff4116p-1 );
305
+ try expectEqual (expm1_32 (0x1.288bbcp+3 ), 0x1.4ab480p+13 ); // Disagrees with GCC in last bit
306
+ try expectEqual (expm1_32 (0x1.52efd0p-1 ), 0x1.e09536p-1 );
307
+ try expectEqual (expm1_32 (-0x1.a05cc8p-2 ), -0x1.561c3ep-2 );
308
+ try expectEqual (expm1_32 (0x1.1f9efap-1 ), 0x1.81ec4ep-1 );
309
+ try expectEqual (expm1_32 (0x1.8c5db0p-1 ), 0x1.2b3364p+0 );
310
+ try expectEqual (expm1_32 (-0x1.5b86eap-1 ), -0x1.f8951ap-2 );
302
311
}
303
312
304
- test expm1_64 {
305
- const epsilon = 0.000001 ;
313
+ test "expm1_32() boundary" {
314
+ // TODO: The last value before inf is actually 0x1.62e300p+6 -> 0x1.ff681ep+127
315
+ // try expectEqual(expm1_32(0x1.62e42ep+6), 0x1.ffff08p+127); // Last value before result is inf
316
+ try expectEqual (expm1_32 (0x1.62e430p+6 ), math .inf (f32 )); // First value that gives inf
317
+ try expectEqual (expm1_32 (0x1.fffffep+127 ), math .inf (f32 )); // Max input value
318
+ try expectEqual (expm1_32 (0x1p-149 ), 0x1p-149 ); // Min positive input value
319
+ try expectEqual (expm1_32 (-0x1p-149 ), -0x1p-149 ); // Min negative input value
320
+ try expectEqual (expm1_32 (0x1p-126 ), 0x1p-126 ); // First positive subnormal input
321
+ try expectEqual (expm1_32 (-0x1p-126 ), -0x1p-126 ); // First negative subnormal input
322
+ try expectEqual (expm1_32 (0x1.fffffep-125 ), 0x1.fffffep-125 ); // Last positive value before subnormal
323
+ try expectEqual (expm1_32 (-0x1.fffffep-125 ), -0x1.fffffep-125 ); // Last negative value before subnormal
324
+ try expectEqual (expm1_32 (-0x1.154244p+4 ), -0x1.fffffep-1 ); // Last value before result is -1
325
+ try expectEqual (expm1_32 (-0x1.154246p+4 ), -1 ); // First value where result is -1
326
+ }
306
327
307
- try expect (math .isPositiveZero (expm1_64 (0.0 )));
308
- try expect (math .approxEqAbs (f64 , expm1_64 (0.0 ), 0.0 , epsilon ));
309
- try expect (math .approxEqAbs (f64 , expm1_64 (0.2 ), 0.221403 , epsilon ));
310
- try expect (math .approxEqAbs (f64 , expm1_64 (0.8923 ), 1.440737 , epsilon ));
311
- try expect (math .approxEqAbs (f64 , expm1_64 (1.5 ), 3.481689 , epsilon ));
328
+ test "expm1_64() special" {
329
+ try expectEqual (expm1_64 (0.0 ), 0.0 );
330
+ try expectEqual (expm1_64 (-0.0 ), 0.0 );
331
+ try expectEqual (expm1_64 (math .ln2 ), 1.0 );
332
+ try expectEqual (expm1_64 (math .inf (f64 )), math .inf (f64 ));
333
+ try expectEqual (expm1_64 (- math .inf (f64 )), -1.0 );
334
+ try expect (math .isNan (expm1_64 (math .nan (f64 ))));
335
+ try expect (math .isNan (expm1_64 (math .snan (f64 ))));
312
336
}
313
337
314
- test "expm1_32.special" {
315
- try expect (math .isPositiveInf (expm1_32 (math .inf (f32 ))));
316
- try expect (expm1_32 (- math .inf (f32 )) == -1.0 );
317
- try expect (math .isNan (expm1_32 (math .nan (f32 ))));
338
+ test "expm1_64() sanity" {
339
+ try expectEqual (expm1_64 (-0x1.02239f3c6a8f1p+3 ), -0x1.ffd6df9b02b3ep-1 );
340
+ try expectEqual (expm1_64 (0x1.161868e18bc67p+2 ), 0x1.30712ed238c04p+6 );
341
+ try expectEqual (expm1_64 (-0x1.0c34b3e01e6e7p+3 ), -0x1.ffe1f94e493e7p-1 );
342
+ try expectEqual (expm1_64 (-0x1.a206f0a19dcc4p+2 ), -0x1.ff4115c03f78dp-1 );
343
+ try expectEqual (expm1_64 (0x1.288bbb0d6a1e6p+3 ), 0x1.4ab477496e07ep+13 );
344
+ try expectEqual (expm1_64 (0x1.52efd0cd80497p-1 ), 0x1.e095382100a01p-1 );
345
+ try expectEqual (expm1_64 (-0x1.a05cc754481d1p-2 ), -0x1.561c3e0582be6p-2 );
346
+ try expectEqual (expm1_64 (0x1.1f9ef934745cbp-1 ), 0x1.81ec4cd4d4a8fp-1 );
347
+ try expectEqual (expm1_64 (0x1.8c5db097f7442p-1 ), 0x1.2b3363a944bf7p+0 );
348
+ try expectEqual (expm1_64 (-0x1.5b86ea8118a0ep-1 ), -0x1.f8951aebffbafp-2 );
318
349
}
319
350
320
- test "expm1_64.special" {
321
- try expect (math .isPositiveInf (expm1_64 (math .inf (f64 ))));
322
- try expect (expm1_64 (- math .inf (f64 )) == -1.0 );
323
- try expect (math .isNan (expm1_64 (math .nan (f64 ))));
351
+ test "expm1_64() boundary" {
352
+ try expectEqual (expm1_64 (0x1.62e42fefa39efp+9 ), 0x1.fffffffffff2ap+1023 ); // Last value before result is inf
353
+ try expectEqual (expm1_64 (0x1.62e42fefa39f0p+9 ), math .inf (f64 )); // First value that gives inf
354
+ try expectEqual (expm1_64 (0x1.fffffffffffffp+1023 ), math .inf (f64 )); // Max input value
355
+ try expectEqual (expm1_64 (0x1p-1074 ), 0x1p-1074 ); // Min positive input value
356
+ try expectEqual (expm1_64 (-0x1p-1074 ), -0x1p-1074 ); // Min negative input value
357
+ try expectEqual (expm1_64 (0x1p-1022 ), 0x1p-1022 ); // First positive subnormal input
358
+ try expectEqual (expm1_64 (-0x1p-1022 ), -0x1p-1022 ); // First negative subnormal input
359
+ try expectEqual (expm1_64 (0x1.fffffffffffffp-1021 ), 0x1.fffffffffffffp-1021 ); // Last positive value before subnormal
360
+ try expectEqual (expm1_64 (-0x1.fffffffffffffp-1021 ), -0x1.fffffffffffffp-1021 ); // Last negative value before subnormal
361
+ try expectEqual (expm1_64 (-0x1.2b708872320e1p+5 ), -0x1.fffffffffffffp-1 ); // Last value before result is -1
362
+ try expectEqual (expm1_64 (-0x1.2b708872320e2p+5 ), -1 ); // First value where result is -1
324
363
}
0 commit comments