2017-06-20 04:01:04 -07:00
|
|
|
// Special Cases:
|
|
|
|
//
|
|
|
|
// - sqrt(+inf) = +inf
|
|
|
|
// - sqrt(+-0) = +-0
|
|
|
|
// - sqrt(x) = nan if x < 0
|
|
|
|
// - sqrt(nan) = nan
|
|
|
|
|
2017-12-23 19:08:53 -08:00
|
|
|
const std = @import("../index.zig");
|
|
|
|
const math = std.math;
|
|
|
|
const assert = std.debug.assert;
|
2017-12-14 16:41:35 -08:00
|
|
|
const builtin = @import("builtin");
|
|
|
|
const TypeId = builtin.TypeId;
|
2017-06-16 01:26:10 -07:00
|
|
|
|
2018-01-25 01:10:11 -08:00
|
|
|
pub fn sqrt(x: var) (if (@typeId(@typeOf(x)) == TypeId.Int) @IntType(false, @typeOf(x).bit_count / 2) else @typeOf(x)) {
|
2017-06-16 01:26:10 -07:00
|
|
|
const T = @typeOf(x);
|
2017-12-14 16:41:35 -08:00
|
|
|
switch (@typeId(T)) {
|
2018-04-15 10:21:52 -07:00
|
|
|
TypeId.FloatLiteral => return T(@sqrt(f64, x)), // TODO upgrade to f128
|
|
|
|
TypeId.Float => return @sqrt(T, x),
|
2017-12-14 16:41:35 -08:00
|
|
|
TypeId.IntLiteral => comptime {
|
|
|
|
if (x > @maxValue(u128)) {
|
|
|
|
@compileError("sqrt not implemented for comptime_int greater than 128 bits");
|
|
|
|
}
|
|
|
|
if (x < 0) {
|
|
|
|
@compileError("sqrt on negative number");
|
|
|
|
}
|
|
|
|
return T(sqrt_int(u128, x));
|
|
|
|
},
|
2018-04-15 10:21:52 -07:00
|
|
|
TypeId.Int => return sqrt_int(T, x),
|
2017-06-16 01:26:10 -07:00
|
|
|
else => @compileError("sqrt not implemented for " ++ @typeName(T)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-19 11:36:33 -07:00
|
|
|
test "math.sqrt" {
|
2018-04-15 10:21:52 -07:00
|
|
|
assert(sqrt(f32(0.0)) == @sqrt(f32, 0.0));
|
|
|
|
assert(sqrt(f64(0.0)) == @sqrt(f64, 0.0));
|
2017-06-16 01:26:10 -07:00
|
|
|
}
|
|
|
|
|
2017-06-19 11:36:33 -07:00
|
|
|
test "math.sqrt32" {
|
2017-06-16 01:26:10 -07:00
|
|
|
const epsilon = 0.000001;
|
|
|
|
|
2018-04-15 10:21:52 -07:00
|
|
|
assert(@sqrt(f32, 0.0) == 0.0);
|
|
|
|
assert(math.approxEq(f32, @sqrt(f32, 2.0), 1.414214, epsilon));
|
|
|
|
assert(math.approxEq(f32, @sqrt(f32, 3.6), 1.897367, epsilon));
|
|
|
|
assert(@sqrt(f32, 4.0) == 2.0);
|
|
|
|
assert(math.approxEq(f32, @sqrt(f32, 7.539840), 2.745877, epsilon));
|
|
|
|
assert(math.approxEq(f32, @sqrt(f32, 19.230934), 4.385309, epsilon));
|
|
|
|
assert(@sqrt(f32, 64.0) == 8.0);
|
|
|
|
assert(math.approxEq(f32, @sqrt(f32, 64.1), 8.006248, epsilon));
|
|
|
|
assert(math.approxEq(f32, @sqrt(f32, 8942.230469), 94.563370, epsilon));
|
2017-06-16 01:26:10 -07:00
|
|
|
}
|
|
|
|
|
2017-06-19 11:36:33 -07:00
|
|
|
test "math.sqrt64" {
|
2017-06-16 01:26:10 -07:00
|
|
|
const epsilon = 0.000001;
|
|
|
|
|
2018-04-15 10:21:52 -07:00
|
|
|
assert(@sqrt(f64, 0.0) == 0.0);
|
|
|
|
assert(math.approxEq(f64, @sqrt(f64, 2.0), 1.414214, epsilon));
|
|
|
|
assert(math.approxEq(f64, @sqrt(f64, 3.6), 1.897367, epsilon));
|
|
|
|
assert(@sqrt(f64, 4.0) == 2.0);
|
|
|
|
assert(math.approxEq(f64, @sqrt(f64, 7.539840), 2.745877, epsilon));
|
|
|
|
assert(math.approxEq(f64, @sqrt(f64, 19.230934), 4.385309, epsilon));
|
|
|
|
assert(@sqrt(f64, 64.0) == 8.0);
|
|
|
|
assert(math.approxEq(f64, @sqrt(f64, 64.1), 8.006248, epsilon));
|
|
|
|
assert(math.approxEq(f64, @sqrt(f64, 8942.230469), 94.563367, epsilon));
|
2017-06-16 01:26:10 -07:00
|
|
|
}
|
2017-06-20 04:01:04 -07:00
|
|
|
|
|
|
|
test "math.sqrt32.special" {
|
2018-04-15 10:21:52 -07:00
|
|
|
assert(math.isPositiveInf(@sqrt(f32, math.inf(f32))));
|
|
|
|
assert(@sqrt(f32, 0.0) == 0.0);
|
|
|
|
assert(@sqrt(f32, -0.0) == -0.0);
|
|
|
|
assert(math.isNan(@sqrt(f32, -1.0)));
|
|
|
|
assert(math.isNan(@sqrt(f32, math.nan(f32))));
|
2017-06-20 04:01:04 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
test "math.sqrt64.special" {
|
2018-04-15 10:21:52 -07:00
|
|
|
assert(math.isPositiveInf(@sqrt(f64, math.inf(f64))));
|
|
|
|
assert(@sqrt(f64, 0.0) == 0.0);
|
|
|
|
assert(@sqrt(f64, -0.0) == -0.0);
|
|
|
|
assert(math.isNan(@sqrt(f64, -1.0)));
|
|
|
|
assert(math.isNan(@sqrt(f64, math.nan(f64))));
|
2017-06-20 04:01:04 -07:00
|
|
|
}
|
2017-12-14 16:41:35 -08:00
|
|
|
|
2018-01-25 01:10:11 -08:00
|
|
|
fn sqrt_int(comptime T: type, value: T) @IntType(false, T.bit_count / 2) {
|
2017-12-14 16:41:35 -08:00
|
|
|
var op = value;
|
|
|
|
var res: T = 0;
|
|
|
|
var one: T = 1 << (T.bit_count - 2);
|
|
|
|
|
|
|
|
// "one" starts at the highest power of four <= than the argument.
|
|
|
|
while (one > op) {
|
|
|
|
one >>= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (one != 0) {
|
|
|
|
if (op >= res + one) {
|
|
|
|
op -= res + one;
|
|
|
|
res += 2 * one;
|
|
|
|
}
|
|
|
|
res >>= 1;
|
|
|
|
one >>= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
const ResultType = @IntType(false, T.bit_count / 2);
|
|
|
|
return ResultType(res);
|
|
|
|
}
|
|
|
|
|
|
|
|
test "math.sqrt_int" {
|
|
|
|
assert(sqrt_int(u32, 3) == 1);
|
|
|
|
assert(sqrt_int(u32, 4) == 2);
|
|
|
|
assert(sqrt_int(u32, 5) == 2);
|
|
|
|
assert(sqrt_int(u32, 8) == 2);
|
|
|
|
assert(sqrt_int(u32, 9) == 3);
|
|
|
|
assert(sqrt_int(u32, 10) == 3);
|
|
|
|
}
|