shithub: mc

Download patch

ref: 5e1154d69efc86f5fe3831b047e3531d9cfd3478
parent: 6fb7d34b848c598e6398f960dc0a7e240e09a6f5
author: S. Gilles <sgilles@math.umd.edu>
date: Mon Mar 12 03:09:31 EDT 2018

Make floor & friends slower, but more readable

--- a/lib/math/fpmath-trunc-impl.myr
+++ b/lib/math/fpmath-trunc-impl.myr
@@ -9,152 +9,95 @@
 	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
+const Flt32NegMask : uint32 = (1 << 31)
+const Flt32SigMask : uint32 = (1 << 23) - 1
 
-	/*
-	   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
+const Flt64NegMask : uint64 = (1 << 63)
+const Flt64SigMask : uint64 = (1 << 52) - 1
 
-	/* 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)
+	var n, e, s
+	(n, e, s) = std.flt32explode(f)
 
 	/* Many special cases */
-	if e >= 23 || u == 0x80000000
+	if e >= 23 || f == -0.0
 		-> f
-	elif (e < 0) && (u & (1 << 31) != 0)
-		-> -1.0
 	elif e < 0
-		-> 0.0
+		if n
+			-> -1.0
+		else
+			-> 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)
+	if n
+		var fractional_mask = Flt32SigMask >> (e : uint32)
+		if s & fractional_mask == 0
+			-> f
+		else
+			/* Turns out the packing of exp and sig is useful */
+			var u : uint32 = std.flt32bits(f) & ~fractional_mask
+			u += ((1 << 23) >> (e : uint32))
+			-> std.flt32frombits(u)
 		;;
-		-> std.flt32frombits(v)
 	;;
 
-	var m : uint32 = ~(((1 << 23) - 1) >> shift_e)
-	var v : uint32 = u & m
-	-> std.flt32frombits(v)
+	var m : uint32 = (Flt32SigMask >> (e : uint32))
+	-> std.flt32assem(n, e, s & ~m)
 }
 
-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
+pkglocal const trunc32 = {f : flt32
+	if std.flt32bits(f) & Flt32NegMask != 0
+		-> -floor32(-f)
+	else
+		-> floor32(f)
 	;;
-
-	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 ceil32 = {f : flt32
+	-> -floor32(-f)
 }
 
 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)
+	var n, e, s
+	(n, e, s) = std.flt64explode(f)
 
-	if e >= 52 || u == 0x8000000000000000ul
+	/* Many special cases */
+	if e >= 52 || f == -0.0
 		-> f
-	elif (e < 0) && (u & (1 << 63) != 0)
-			-> -1.0
 	elif e < 0
-		-> 0.0
+		if n
+			-> -1.0
+		else
+			-> 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)
+	if n
+		var fractional_mask = Flt64SigMask >> (e : uint64)
+		if s & fractional_mask == 0
+			-> f
+		else
+			/* Turns out the packing of exp and sig is useful */
+			var u : uint64 = std.flt64bits(f) & ~fractional_mask
+			u += ((1 << 52) >> (e : uint64))
+			-> std.flt64frombits(u)
 		;;
-		-> std.flt64frombits(v)
 	;;
 
-	var m : uint64 = ~(((1 << 52) - 1) >> shift_e)
-	var v : uint64 = u & m
-	-> std.flt64frombits(v)
+	var m : uint64 = (Flt64SigMask >> (e : uint64))
+	-> std.flt64assem(n, e, s & ~m)
 }
 
-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
+pkglocal const trunc64 = {f : flt64
+	if std.flt64bits(f) & Flt64NegMask != 0
+		-> -floor64(-f)
+	else
+		-> floor64(f)
 	;;
+}
 
-	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 : flt64
+	-> -floor64(-f)
 }
+
--- a/lib/math/test/fpmath-trunc-impl.myr
+++ b/lib/math/test/fpmath-trunc-impl.myr
@@ -58,6 +58,9 @@
 		(10664524000000000000.0, 10664524000000000000.0),
 		(-3.5, -4.0),
 		(-101.999, -102.0),
+		(-126.999, -127.0),
+		(-127.999, -128.0),
+		(-128.999, -129.0),
 		(std.flt32nan(), std.flt32nan()),
 	][:]