Skip to content

Commit

Permalink
Switch to struct return type instead of out values
Browse files Browse the repository at this point in the history
See #7.
  • Loading branch information
tiehuis committed Jun 12, 2017
1 parent cad9522 commit fdc2904
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 128 deletions.
16 changes: 10 additions & 6 deletions src/fma.zig
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,16 @@ fn fma64(x: f64, y: f64, z: f64) -> f64 {
return x * y;
}

var ex: i32 = undefined;
var ey: i32 = undefined;
var ez: i32 = undefined;
var xs = fmath.frexp(x, &ex);
var ys = fmath.frexp(y, &ey);
var zs = fmath.frexp(z, &ez);
const x1 = fmath.frexp(x);
var ex = x1.exponent;
var xs = x1.significand;
const x2 = fmath.frexp(y);
var ey = x2.exponent;
var ys = x2.significand;
const x3 = fmath.frexp(z);
var ez = x3.exponent;
var zs = x3.significand;

var spread = ex + ey - ez;

// TODO: Other rounding modes handled edge cases here.
Expand Down
104 changes: 61 additions & 43 deletions src/frexp.zig
Original file line number Diff line number Diff line change
@@ -1,88 +1,106 @@
const fmath = @import("index.zig");

pub fn frexp(x: var, e: &i32) -> @typeOf(x) {
fn frexp_result(comptime T: type) -> type {
struct {
significand: T,
exponent: i32,
}
}
pub const frexp32_result = frexp_result(f32);
pub const frexp64_result = frexp_result(f64);

pub fn frexp(x: var) -> frexp_result(@typeOf(x)) {
const T = @typeOf(x);
switch (T) {
f32 => @inlineCall(frexp32, x, e),
f64 => @inlineCall(frexp64, x, e),
f32 => @inlineCall(frexp32, x),
f64 => @inlineCall(frexp64, x),
else => @compileError("frexp not implemented for " ++ @typeName(T)),
}
}

fn frexp32(x_: f32, e: &i32) -> f32 {
var x = x_;
fn frexp32(x: f32) -> frexp32_result {
var result: frexp32_result = undefined;

var y = fmath.bitCast(u32, x);
const ee = i32(y >> 23) & 0xFF;
const e = i32(y >> 23) & 0xFF;

if (ee == 0) {
if (e == 0) {
if (x != 0) {
x = frexp32(x * 0x1.0p64, e);
*e -= 64;
result = frexp32(x * 0x1.0p64);
result.exponent -= 64;
} else {
*e = 0;
result.significand = x;
result.exponent = 0;
}
return x;
} else if (ee == 0xFF) {
return x;
return result;
} else if (e == 0xFF) {
result.significand = x;
// TODO: Any worthwhile value to set exponent to in this case?
return result;
}

*e = ee - 0x7E;
result.exponent = e - 0x7E;
y &= 0x807FFFFF;
y |= 0x3F000000;
fmath.bitCast(f32, y)
result.significand = fmath.bitCast(f32, y);
result
}

fn frexp64(x_: f64, e: &i32) -> f64 {
var x = x_;
fn frexp64(x: f64) -> frexp64_result {
var result: frexp64_result = undefined;

var y = fmath.bitCast(u64, x);
const ee = i32(y >> 52) & 0x7FF;
const e = i32(y >> 52) & 0x7FF;

if (ee == 0) {
if (e == 0) {
if (x != 0) {
x = frexp64(x * 0x1.0p64, e);
*e -= 64;
result = frexp64(x * 0x1.0p64);
result.exponent -= 64;
} else {
*e = 0;
result.significand = x;
result.exponent = 0;
}
return x;
} else if (ee == 0x7FF) {
return x;
return result;
} else if (e == 0x7FF) {
result.significand = x;
return result;
}

*e = ee - 0x3FE;
result.exponent = e - 0x3FE;
y &= 0x800FFFFFFFFFFFFF;
y |= 0x3FE0000000000000;
fmath.bitCast(f64, y)
result.significand = fmath.bitCast(f64, y);
result
}

test "frexp" {
var i0: i32 = undefined;
var i1: i32 = undefined;
const a = frexp(f32(1.3));
const b = frexp32(1.3);
fmath.assert(a.significand == b.significand and a.exponent == b.exponent);

fmath.assert(frexp(f32(1.3), &i0) == frexp32(1.3, &i1));
fmath.assert(frexp(f64(1.3), &i0) == frexp64(1.3, &i1));
const c = frexp(f64(1.3));
const d = frexp64(1.3);
fmath.assert(c.significand == d.significand and c.exponent == d.exponent);
}

test "frexp32" {
const epsilon = 0.000001;
var i: i32 = undefined;
var d: f32 = undefined;
var r: frexp32_result = undefined;

d = frexp32(1.3, &i);
fmath.assert(fmath.approxEq(f32, d, 0.65, epsilon) and i == 1);
r = frexp32(1.3);
fmath.assert(fmath.approxEq(f32, r.significand, 0.65, epsilon) and r.exponent == 1);

d = frexp32(78.0234, &i);
fmath.assert(fmath.approxEq(f32, d, 0.609558, epsilon) and i == 7);
r = frexp32(78.0234);
fmath.assert(fmath.approxEq(f32, r.significand, 0.609558, epsilon) and r.exponent == 7);
}

test "frexp64" {
const epsilon = 0.000001;
var i: i32 = undefined;
var d: f64 = undefined;
var r: frexp64_result = undefined;

d = frexp64(1.3, &i);
fmath.assert(fmath.approxEq(f64, d, 0.65, epsilon) and i == 1);
r = frexp64(1.3);
fmath.assert(fmath.approxEq(f64, r.significand, 0.65, epsilon) and r.exponent == 1);

d = frexp64(78.0234, &i);
fmath.assert(fmath.approxEq(f64, d, 0.609558, epsilon) and i == 7);
r = frexp64(78.0234);
fmath.assert(fmath.approxEq(f64, r.significand, 0.609558, epsilon) and r.exponent == 7);
}
4 changes: 4 additions & 0 deletions src/index.zig
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,12 @@ pub const floor = @import("floor.zig").floor;
pub const trunc = @import("floor.zig").trunc;
pub const round = @import("round.zig").round;
pub const frexp = @import("frexp.zig").frexp;
pub const frexp32_result = @import("frexp.zig").frexp32_result;
pub const frexp64_result = @import("frexp.zig").frexp64_result;
pub const fmod = @import("fmod.zig").fmod;
pub const modf = @import("modf.zig").modf;
pub const modf32_result = @import("modf.zig").modf32_result;
pub const modf64_result = @import("modf.zig").modf64_result;
pub const copysign = @import("copysign.zig").copysign;
pub const isFinite = @import("isfinite.zig").isFinite;
pub const isInf = @import("isinf.zig").isInf;
Expand Down
Loading

0 comments on commit fdc2904

Please sign in to comment.