[Mesa-dev] [PATCH] softpipe: Do round-to-even, not round-up.
Olivier Galibert
galibert at pobox.com
Fri May 18 02:43:28 PDT 2012
Fixes the piglit roundEven tests.
Signed-off-by: Olivier Galibert <galibert at pobox.com>
---
src/gallium/auxiliary/tgsi/tgsi_exec.c | 76 ++++++++++++++++++++++++++++++--
1 file changed, 72 insertions(+), 4 deletions(-)
diff --git a/src/gallium/auxiliary/tgsi/tgsi_exec.c b/src/gallium/auxiliary/tgsi/tgsi_exec.c
index 5e23f5d..7311f5f 100644
--- a/src/gallium/auxiliary/tgsi/tgsi_exec.c
+++ b/src/gallium/auxiliary/tgsi/tgsi_exec.c
@@ -316,14 +316,82 @@ micro_rcp(union tgsi_exec_channel *dst,
dst->f[3] = 1.0f / src->f[3];
}
+static float
+ieee754_fp32_round_half_to_even(float v)
+{
+ unsigned int iv;
+ int exponent;
+ unsigned int one_half_bit_mask, fractional_bits_mask;
+ assert(sizeof(v) == 4);
+ assert(sizeof(iv) == 4);
+ memcpy(&iv, &v, 4);
+
+ exponent = ((iv >> 23) & 0xff) - 0x7f;
+
+ // Integer or nan, return unscathed
+ if (exponent >= 23)
+ return v;
+
+ // abs(v) < 0.5, zero, or denormal, return 0
+ if (exponent < -1)
+ return 0;
+
+ // abs(v) >= 0.5 and < 1
+ if (exponent == -1) {
+ // Not exactly 0.5 round to the to appropriate 1, otherwise to 0
+ if (iv & 0x7fffff) {
+ iv = (iv & 0x80000000) | 0x3f800000;
+ memcpy(&v, &iv, 4);
+ return v;
+ } else
+ return 0;
+ }
+
+ one_half_bit_mask = 0x800000 >> (exponent+1);
+ fractional_bits_mask = 0xffffff >> (exponent+1);
+
+ // Fractional part under 0.5, cutoff the fractional part
+ if (!(iv & one_half_bit_mask)) {
+ iv = iv & ~fractional_bits_mask;
+ memcpy(&v, &iv, 4);
+ return v;
+ }
+
+ // Fractional part over 0.5, round up
+ if ((iv & fractional_bits_mask) != one_half_bit_mask) {
+ // Round up by setting the fractional bits to 1 and incrementing.
+ // The exponent will be automagically incremented when needed
+ // through carry propagation.
+ iv = (iv | fractional_bits_mask) + 1;
+ memcpy(&v, &iv, 4);
+ return v;
+ }
+
+ // Fractional part exactly 0.5, round towards even.
+
+ // Test the bit just over the decimal point to test for oddness. It
+ // works for the borderline case 1.5 because the exponent is 127 in
+ // that case, i.e. the tested bit is the expected 1.
+
+ // Odd, round up
+ if (iv & (one_half_bit_mask << 1))
+ iv = (iv | fractional_bits_mask) + 1;
+ // Even, round down
+ else
+ iv = iv & ~fractional_bits_mask;
+
+ memcpy(&v, &iv, 4);
+ return v;
+}
+
static void
micro_rnd(union tgsi_exec_channel *dst,
const union tgsi_exec_channel *src)
{
- dst->f[0] = floorf(src->f[0] + 0.5f);
- dst->f[1] = floorf(src->f[1] + 0.5f);
- dst->f[2] = floorf(src->f[2] + 0.5f);
- dst->f[3] = floorf(src->f[3] + 0.5f);
+ dst->f[0] = ieee754_fp32_round_half_to_even(src->f[0]);
+ dst->f[1] = ieee754_fp32_round_half_to_even(src->f[1]);
+ dst->f[2] = ieee754_fp32_round_half_to_even(src->f[2]);
+ dst->f[3] = ieee754_fp32_round_half_to_even(src->f[3]);
}
static void
--
1.7.10.rc3.1.gb306
More information about the mesa-dev
mailing list