2019-04-30 23:15:57 -07:00
|
|
|
// Ported from musl, which is licensed under the MIT license:
|
|
|
|
// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
|
2017-06-20 04:01:04 -07:00
|
|
|
//
|
2019-04-30 23:15:57 -07:00
|
|
|
// https://git.musl-libc.org/cgit/musl/tree/src/math/frexpf.c
|
|
|
|
// https://git.musl-libc.org/cgit/musl/tree/src/math/frexp.c
|
2017-06-20 04:01:04 -07:00
|
|
|
|
2019-03-02 13:46:04 -08:00
|
|
|
const std = @import("../std.zig");
|
2017-12-23 19:08:53 -08:00
|
|
|
const math = std.math;
|
2019-02-08 15:18:47 -08:00
|
|
|
const expect = std.testing.expect;
|
2017-06-07 19:56:57 -07:00
|
|
|
|
2018-01-25 01:10:11 -08:00
|
|
|
fn frexp_result(comptime T: type) type {
|
2018-11-13 05:08:37 -08:00
|
|
|
return struct {
|
2017-06-16 01:26:10 -07:00
|
|
|
significand: T,
|
|
|
|
exponent: i32,
|
2017-12-21 21:50:30 -08:00
|
|
|
};
|
2017-06-16 01:26:10 -07:00
|
|
|
}
|
|
|
|
pub const frexp32_result = frexp_result(f32);
|
|
|
|
pub const frexp64_result = frexp_result(f64);
|
|
|
|
|
2019-04-30 23:15:57 -07:00
|
|
|
/// Breaks x into a normalized fraction and an integral power of two.
|
|
|
|
/// f == frac * 2^exp, with |frac| in the interval [0.5, 1).
|
|
|
|
///
|
|
|
|
/// Special Cases:
|
|
|
|
/// - frexp(+-0) = +-0, 0
|
|
|
|
/// - frexp(+-inf) = +-inf, 0
|
|
|
|
/// - frexp(nan) = nan, undefined
|
2019-12-09 12:56:19 -08:00
|
|
|
pub fn frexp(x: var) frexp_result(@TypeOf(x)) {
|
|
|
|
const T = @TypeOf(x);
|
2017-12-21 21:50:30 -08:00
|
|
|
return switch (T) {
|
2017-12-22 10:14:07 -08:00
|
|
|
f32 => frexp32(x),
|
|
|
|
f64 => frexp64(x),
|
2017-06-07 19:56:57 -07:00
|
|
|
else => @compileError("frexp not implemented for " ++ @typeName(T)),
|
2017-12-21 21:50:30 -08:00
|
|
|
};
|
2017-06-07 19:56:57 -07:00
|
|
|
}
|
|
|
|
|
2018-01-25 01:10:11 -08:00
|
|
|
fn frexp32(x: f32) frexp32_result {
|
2017-06-16 01:26:10 -07:00
|
|
|
var result: frexp32_result = undefined;
|
|
|
|
|
2017-06-07 19:56:57 -07:00
|
|
|
var y = @bitCast(u32, x);
|
2018-06-16 23:57:07 -07:00
|
|
|
const e = @intCast(i32, y >> 23) & 0xFF;
|
2017-06-07 19:56:57 -07:00
|
|
|
|
2017-06-16 01:26:10 -07:00
|
|
|
if (e == 0) {
|
2017-06-07 19:56:57 -07:00
|
|
|
if (x != 0) {
|
2017-06-16 01:26:10 -07:00
|
|
|
// subnormal
|
|
|
|
result = frexp32(x * 0x1.0p64);
|
|
|
|
result.exponent -= 64;
|
2017-06-07 19:56:57 -07:00
|
|
|
} else {
|
2017-06-16 01:26:10 -07:00
|
|
|
// frexp(+-0) = (+-0, 0)
|
|
|
|
result.significand = x;
|
|
|
|
result.exponent = 0;
|
2017-06-07 19:56:57 -07:00
|
|
|
}
|
2017-06-16 01:26:10 -07:00
|
|
|
return result;
|
|
|
|
} else if (e == 0xFF) {
|
2017-06-22 00:29:57 -07:00
|
|
|
// frexp(nan) = (nan, undefined)
|
2017-06-16 01:26:10 -07:00
|
|
|
result.significand = x;
|
2017-06-22 00:29:57 -07:00
|
|
|
result.exponent = undefined;
|
|
|
|
|
|
|
|
// frexp(+-inf) = (+-inf, 0)
|
|
|
|
if (math.isInf(x)) {
|
|
|
|
result.exponent = 0;
|
|
|
|
}
|
|
|
|
|
2017-06-16 01:26:10 -07:00
|
|
|
return result;
|
2017-06-07 19:56:57 -07:00
|
|
|
}
|
|
|
|
|
2017-06-16 01:26:10 -07:00
|
|
|
result.exponent = e - 0x7E;
|
2017-06-07 19:56:57 -07:00
|
|
|
y &= 0x807FFFFF;
|
|
|
|
y |= 0x3F000000;
|
2017-06-16 01:26:10 -07:00
|
|
|
result.significand = @bitCast(f32, y);
|
2017-12-21 21:50:30 -08:00
|
|
|
return result;
|
2017-06-07 19:56:57 -07:00
|
|
|
}
|
|
|
|
|
2018-01-25 01:10:11 -08:00
|
|
|
fn frexp64(x: f64) frexp64_result {
|
2017-06-16 01:26:10 -07:00
|
|
|
var result: frexp64_result = undefined;
|
|
|
|
|
2017-06-07 19:56:57 -07:00
|
|
|
var y = @bitCast(u64, x);
|
2018-06-16 23:57:07 -07:00
|
|
|
const e = @intCast(i32, y >> 52) & 0x7FF;
|
2017-06-07 19:56:57 -07:00
|
|
|
|
2017-06-16 01:26:10 -07:00
|
|
|
if (e == 0) {
|
2017-06-07 19:56:57 -07:00
|
|
|
if (x != 0) {
|
2017-06-16 01:26:10 -07:00
|
|
|
// subnormal
|
|
|
|
result = frexp64(x * 0x1.0p64);
|
|
|
|
result.exponent -= 64;
|
2017-06-07 19:56:57 -07:00
|
|
|
} else {
|
2017-06-16 01:26:10 -07:00
|
|
|
// frexp(+-0) = (+-0, 0)
|
|
|
|
result.significand = x;
|
|
|
|
result.exponent = 0;
|
2017-06-07 19:56:57 -07:00
|
|
|
}
|
2017-06-16 01:26:10 -07:00
|
|
|
return result;
|
|
|
|
} else if (e == 0x7FF) {
|
2017-06-22 00:29:57 -07:00
|
|
|
// frexp(nan) = (nan, undefined)
|
2017-06-16 01:26:10 -07:00
|
|
|
result.significand = x;
|
2017-06-22 00:29:57 -07:00
|
|
|
result.exponent = undefined;
|
|
|
|
|
|
|
|
// frexp(+-inf) = (+-inf, 0)
|
|
|
|
if (math.isInf(x)) {
|
|
|
|
result.exponent = 0;
|
|
|
|
}
|
|
|
|
|
2017-06-16 01:26:10 -07:00
|
|
|
return result;
|
2017-06-07 19:56:57 -07:00
|
|
|
}
|
|
|
|
|
2017-06-16 01:26:10 -07:00
|
|
|
result.exponent = e - 0x3FE;
|
2017-06-07 19:56:57 -07:00
|
|
|
y &= 0x800FFFFFFFFFFFFF;
|
|
|
|
y |= 0x3FE0000000000000;
|
2017-06-16 01:26:10 -07:00
|
|
|
result.significand = @bitCast(f64, y);
|
2017-12-21 21:50:30 -08:00
|
|
|
return result;
|
2017-06-07 19:56:57 -07:00
|
|
|
}
|
|
|
|
|
2017-06-19 11:36:33 -07:00
|
|
|
test "math.frexp" {
|
2019-11-06 20:25:57 -08:00
|
|
|
const a = frexp(@as(f32, 1.3));
|
2017-06-16 01:26:10 -07:00
|
|
|
const b = frexp32(1.3);
|
2019-02-08 15:18:47 -08:00
|
|
|
expect(a.significand == b.significand and a.exponent == b.exponent);
|
2017-06-07 19:56:57 -07:00
|
|
|
|
2019-11-06 20:25:57 -08:00
|
|
|
const c = frexp(@as(f64, 1.3));
|
2017-06-16 01:26:10 -07:00
|
|
|
const d = frexp64(1.3);
|
2019-02-08 15:18:47 -08:00
|
|
|
expect(c.significand == d.significand and c.exponent == d.exponent);
|
2017-06-07 19:56:57 -07:00
|
|
|
}
|
|
|
|
|
2017-06-19 11:36:33 -07:00
|
|
|
test "math.frexp32" {
|
2017-06-07 19:56:57 -07:00
|
|
|
const epsilon = 0.000001;
|
2017-06-16 01:26:10 -07:00
|
|
|
var r: frexp32_result = undefined;
|
2017-06-07 19:56:57 -07:00
|
|
|
|
2017-06-16 01:26:10 -07:00
|
|
|
r = frexp32(1.3);
|
2019-02-08 15:18:47 -08:00
|
|
|
expect(math.approxEq(f32, r.significand, 0.65, epsilon) and r.exponent == 1);
|
2017-06-07 19:56:57 -07:00
|
|
|
|
2017-06-16 01:26:10 -07:00
|
|
|
r = frexp32(78.0234);
|
2019-02-08 15:18:47 -08:00
|
|
|
expect(math.approxEq(f32, r.significand, 0.609558, epsilon) and r.exponent == 7);
|
2017-06-07 19:56:57 -07:00
|
|
|
}
|
|
|
|
|
2017-06-19 11:36:33 -07:00
|
|
|
test "math.frexp64" {
|
2017-06-07 19:56:57 -07:00
|
|
|
const epsilon = 0.000001;
|
2017-06-16 01:26:10 -07:00
|
|
|
var r: frexp64_result = undefined;
|
2017-06-07 19:56:57 -07:00
|
|
|
|
2017-06-16 01:26:10 -07:00
|
|
|
r = frexp64(1.3);
|
2019-02-08 15:18:47 -08:00
|
|
|
expect(math.approxEq(f64, r.significand, 0.65, epsilon) and r.exponent == 1);
|
2017-06-07 19:56:57 -07:00
|
|
|
|
2017-06-16 01:26:10 -07:00
|
|
|
r = frexp64(78.0234);
|
2019-02-08 15:18:47 -08:00
|
|
|
expect(math.approxEq(f64, r.significand, 0.609558, epsilon) and r.exponent == 7);
|
2017-06-07 19:56:57 -07:00
|
|
|
}
|
2017-06-20 04:01:04 -07:00
|
|
|
|
|
|
|
test "math.frexp32.special" {
|
|
|
|
var r: frexp32_result = undefined;
|
|
|
|
|
|
|
|
r = frexp32(0.0);
|
2019-02-08 15:18:47 -08:00
|
|
|
expect(r.significand == 0.0 and r.exponent == 0);
|
2017-06-20 04:01:04 -07:00
|
|
|
|
|
|
|
r = frexp32(-0.0);
|
2019-02-08 15:18:47 -08:00
|
|
|
expect(r.significand == -0.0 and r.exponent == 0);
|
2017-06-20 04:01:04 -07:00
|
|
|
|
|
|
|
r = frexp32(math.inf(f32));
|
2019-02-08 15:18:47 -08:00
|
|
|
expect(math.isPositiveInf(r.significand) and r.exponent == 0);
|
2017-06-20 04:01:04 -07:00
|
|
|
|
|
|
|
r = frexp32(-math.inf(f32));
|
2019-02-08 15:18:47 -08:00
|
|
|
expect(math.isNegativeInf(r.significand) and r.exponent == 0);
|
2017-06-20 04:01:04 -07:00
|
|
|
|
|
|
|
r = frexp32(math.nan(f32));
|
2019-02-08 15:18:47 -08:00
|
|
|
expect(math.isNan(r.significand));
|
2017-06-20 04:01:04 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
test "math.frexp64.special" {
|
|
|
|
var r: frexp64_result = undefined;
|
|
|
|
|
|
|
|
r = frexp64(0.0);
|
2019-02-08 15:18:47 -08:00
|
|
|
expect(r.significand == 0.0 and r.exponent == 0);
|
2017-06-20 04:01:04 -07:00
|
|
|
|
|
|
|
r = frexp64(-0.0);
|
2019-02-08 15:18:47 -08:00
|
|
|
expect(r.significand == -0.0 and r.exponent == 0);
|
2017-06-20 04:01:04 -07:00
|
|
|
|
|
|
|
r = frexp64(math.inf(f64));
|
2019-02-08 15:18:47 -08:00
|
|
|
expect(math.isPositiveInf(r.significand) and r.exponent == 0);
|
2017-06-20 04:01:04 -07:00
|
|
|
|
|
|
|
r = frexp64(-math.inf(f64));
|
2019-02-08 15:18:47 -08:00
|
|
|
expect(math.isNegativeInf(r.significand) and r.exponent == 0);
|
2017-06-20 04:01:04 -07:00
|
|
|
|
|
|
|
r = frexp64(math.nan(f64));
|
2019-02-08 15:18:47 -08:00
|
|
|
expect(math.isNan(r.significand));
|
2017-06-20 04:01:04 -07:00
|
|
|
}
|