module math

// special cases are:
// sqrt(+inf) = +inf
// sqrt(±0) = ±0
// sqrt(x < 0) = nan
// sqrt(nan) = nan
[inline]
pub fn sqrt(a f64) f64 {
	mut x := a
	if x == 0.0 || is_nan(x) || is_inf(x, 1) {
		return x
	}
	if x < 0.0 {
		return nan()
	}
	z, ex := frexp(x)
	w := x
	// approximate square root of number between 0.5 and 1
	// relative error of approximation = 7.47e-3
	x = 4.173075996388649989089e-1 + 5.9016206709064458299663e-1 * z // adjust for odd powers of 2
	if (ex & 1) != 0 {
		x *= sqrt2
	}
	x = ldexp(x, ex >> 1)
	// newton iterations
	x = 0.5 * (x + w / x)
	x = 0.5 * (x + w / x)
	x = 0.5 * (x + w / x)
	return x
}

// sqrtf calculates square-root of the provided value. (float32)
[inline]
pub fn sqrtf(a f32) f32 {
	return f32(sqrt(a))
}

// sqrti calculates the integer square-root of the provided value. (i64)
pub fn sqrti(a i64) i64 {
	mut x := a
	mut q, mut r := i64(1), i64(0)
	for ; q <= x; {
		q <<= 2
	}
	for ; q > 1; {
		q >>= 2
		t := x - r - q
		r >>= 1
		if t >= 0 {
			x = t
			r += q
		}
	}
	return r
}