shithub: mc

ref: 6fb7d34b848c598e6398f960dc0a7e240e09a6f5
dir: /lib/math/fpmath-trunc-impl.myr/

View raw version
use std

pkg math =
	pkglocal const trunc32 : (f : flt32 -> flt32)
	pkglocal const floor32 : (f : flt32 -> flt32)
	pkglocal const ceil32  : (f : flt32 -> flt32)
	pkglocal const trunc64 : (f : flt64 -> flt64)
	pkglocal const floor64 : (f : flt64 -> flt64)
	pkglocal const ceil64  : (f : flt64 -> flt64)
;;

pkglocal const trunc32 = {f : flt32
	var u : uint32 = std.flt32bits(f)
	var e : uint32 = (((u >> 23) & 0xff) : uint32) - 127
	var e_lt_zero : uint32 = ((e >> 31) : uint32) & 0x1
	var e_ge_zero : uint32 = 1 - e_lt_zero
	var e_ge_23 : uint32 = 1 - ((e - 23) >> 31)
	/*
	   The significand 1 . m1 m2 ... m23 needs to be
	   truncated, which corresponds to zeroing all mi
	   bits where i is beyond the exponent e (they are
	   the actual sub-integer portion).
	 */
	var m : uint32 = ~(((1 << 23) - 1) >> e)
	m |= (-1 : uint32) * e_ge_23
	var v_ge_zero : uint32 = (u & m) * e_ge_zero

	/*
	   On the other hand, if the exponent is < 0, "23
	   - e" is garbage, and we should just return +/-
	   zero
	 */
	var v_lt_zero : uint32 = (u & (1 << 31)) * e_lt_zero

	/* Try to save a branch */
	var v : uint32 = v_ge_zero + v_lt_zero
	-> std.flt32frombits(v)
}

pkglocal const floor32 = {f : flt32
	var u : uint32 = std.flt32bits(f)
	var e : int32 = (((u >> 23) & 0xff) : int32) - 127
	var shift_e : uint32 = (e : uint32)

	/* Many special cases */
	if e >= 23 || u == 0x80000000
		-> f
	elif (e < 0) && (u & (1 << 31) != 0)
		-> -1.0
	elif e < 0
		-> 0.0
	;;

	if u & (1 << 31) != 0
		var fractional_mask : uint32 = (((1 << 23) - 1) >> shift_e)
		var v : uint32 = u & ~fractional_mask
		if (u & fractional_mask) != 0
			v += ((1 << 23) >> shift_e)
		;;
		-> std.flt32frombits(v)
	;;

	var m : uint32 = ~(((1 << 23) - 1) >> shift_e)
	var v : uint32 = u & m
	-> std.flt32frombits(v)
}

pkglocal const ceil32 = {f;
	var u : uint32 = std.flt32bits(f)
	var e : int32 = (((u >> 23) & 0xff) : int32) - 127
	var shift_e : uint32 = (e : uint32)
	if e >= 23 || u == 0x0
		-> f
	elif (e < 0) && (u & (1 << 31) == 0)
		-> 1.0
	elif e < 0
		-> -0.0
	;;

	if u & (1 << 31) == 0
		var fractional_mask : uint32 = (((1 << 23) - 1) >> shift_e)
		var v : uint32 = u & ~fractional_mask
		if (u & fractional_mask) != 0
			v += ((1 << 23) >> shift_e)
		;;
		-> std.flt32frombits(v)
	;;

	var m : uint32 = ~(((1 << 23) - 1) >> shift_e)
	var v : uint32 = u & m
	-> std.flt32frombits(v)
}

pkglocal const trunc64 = {f : flt64
	var u : uint64 = std.flt64bits(f)
	var e : uint64 = (((u >> 52) & 0x7ff) : uint64) - 1023
	var e_lt_zero : uint64 = ((e >> 63) : uint64) & 0x1
	var e_ge_zero : uint64 = 1 - e_lt_zero
	var e_ge_52 : uint64 = 1 - ((e - 52) >> 63)
	var m : uint64 = ~(((1 << 52) - 1) >> e)
	m |= (-1 : uint64) * e_ge_52
	var v_ge_zero : uint64 = (u & m) * e_ge_zero
	var v_lt_zero : uint64 = (u & (1 << 63)) * e_lt_zero
	var v : uint64 = v_ge_zero + v_lt_zero
	-> std.flt64frombits(v)
}

pkglocal const floor64 = {f : flt64
	var u : uint64 = std.flt64bits(f)
	var e : int64 = (((u >> 52) & 0x7ff) : int64) - 1023
	var shift_e : uint64 = (e : uint64)

	if e >= 52 || u == 0x8000000000000000ul
		-> f
	elif (e < 0) && (u & (1 << 63) != 0)
			-> -1.0
	elif e < 0
		-> 0.0
	;;

	if u & (1 << 63) != 0
		var fractional_mask : uint64 = (((1 << 52) - 1) >> shift_e)
		var v : uint64 = u & ~fractional_mask
		if (u & fractional_mask) != 0
			v += ((1 << 52) >> shift_e)
		;;
		-> std.flt64frombits(v)
	;;

	var m : uint64 = ~(((1 << 52) - 1) >> shift_e)
	var v : uint64 = u & m
	-> std.flt64frombits(v)
}

pkglocal const ceil64 = {f;
	var u : uint64 = std.flt64bits(f)
	var e : int64 = (((u >> 52) & 0x7ff) : int64) - 1023
	var shift_e : uint64 = (e : uint64)

	if e >= 52 || u == 0x0ul
		-> f
	elif (e < 0) && (u & (1 << 63) == 0)
			-> 1.0
	elif e < 0
		-> -0.0
	;;

	if u & (1 << 63) == 0
		var fractional_mask : uint64 = (((1 << 52) - 1) >> shift_e)
		var v : uint64 = u & ~fractional_mask
		if (u & fractional_mask) != 0
			v += ((1 << 52) >> shift_e)
		;;
		-> std.flt64frombits(v)
	;;

	var m : uint64 = ~(((1 << 52) - 1) >> shift_e)
	var v : uint64 = u & m
	-> std.flt64frombits(v)
}