[PATCH] dix: add utility functions for double to/fro FP1616/FP3232 conversion
Peter Hutterer
peter.hutterer at who-t.net
Tue Oct 4 16:39:19 PDT 2011
Co-authored by Jeremy Huddleston <jeremyhu at apple.com>
Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
Jeremy, these are your functions fixed up to pass the tests (a few bitshifts
where wrong).
Changes to your version:
- use trunc instad of (double)(int)(double_value)
- use rint(trunc()) instead of (int) to silence gcc
- fix a few wrong bitshifts/masks
- fix < 0 to < 1 for fabs(frac)
dix/inpututils.c | 68 ++++++++++++++++++++++++++++
include/inpututils.h | 6 +++
test/input.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 194 insertions(+), 0 deletions(-)
diff --git a/dix/inpututils.c b/dix/inpututils.c
index 582135e..c27e16c 100644
--- a/dix/inpututils.c
+++ b/dix/inpututils.c
@@ -821,3 +821,71 @@ input_option_set_value(InputOption *opt, const char *value)
if (value)
opt->value = strdup(value);
}
+
+
+/* FP1616/FP3232 conversion functions */
+double
+fp1616_to_double(FP1616 in)
+{
+ double ret;
+ ret = (double)(in >> 16);
+ ret += ldexp((double)(in & 0xffff), -16);
+ return ret;
+}
+
+double
+fp3232_to_double(FP3232 in)
+{
+ double ret;
+ ret = (double)in.integral;
+ ret += ldexp((double)in.frac, -32);
+ return ret;
+}
+
+
+FP1616
+double_to_fp1616(double in)
+{
+ FP1616 ret;
+ int32_t integral;
+ double frac_f;
+ uint32_t frac_d;
+
+ integral = (int32_t)in << 16;
+ frac_f = in - trunc(in);
+
+ if (fabs(frac_f) < 1) {
+ frac_d = rint(trunc(ldexp(frac_f, 16)));
+ } else {
+ /* crap */
+ frac_d = 0;
+ }
+
+ ret = integral;
+ ret |= frac_d & 0xffff;
+ return ret;
+}
+
+FP3232
+double_to_fp3232(double in)
+{
+ FP3232 ret;
+ int32_t integral;
+ double frac_f;
+ uint32_t frac_d;
+
+ integral = (int32_t)in;
+ frac_f = in - trunc(in);
+
+ if (fabs(frac_f) < 1) {
+ frac_d = rint(trunc(ldexp(frac_f,32)));
+ } else {
+ /* crap */
+ frac_d = 0;
+ }
+
+ ret.integral = integral;
+ ret.frac = frac_d;
+ return ret;
+}
+
diff --git a/include/inpututils.h b/include/inpututils.h
index 47e242d..2832ed5 100644
--- a/include/inpututils.h
+++ b/include/inpututils.h
@@ -30,6 +30,7 @@
#define INPUTUTILS_H
#include "input.h"
+#include <X11/extensions/XI2proto.h>
struct _ValuatorMask {
int8_t last_bit; /* highest bit set in mask */
@@ -40,4 +41,9 @@ struct _ValuatorMask {
extern void verify_internal_event(const InternalEvent *ev);
extern void init_device_event(DeviceEvent *event, DeviceIntPtr dev, Time ms);
+FP3232 double_to_fp3232(double in);
+FP1616 double_to_fp1616(double in);
+double fp1616_to_double(FP1616 in);
+double fp3232_to_double(FP3232 in);
+
#endif
diff --git a/test/input.c b/test/input.c
index 5fb9a90..05ef3ac 100644
--- a/test/input.c
+++ b/test/input.c
@@ -1476,8 +1476,128 @@ static void input_option_test(void)
}
+static void
+_test_double_fp16_values(double d)
+{
+ FP1616 fp16;
+ double re;
+ uint32_t frac;
+ int32_t integral;
+
+ if (d > 0x7FFF) {
+ printf("Test out of range\n");
+ assert(0);
+ }
+
+ frac = rint(trunc(ldexp(d - trunc(d), 16)));
+ integral = ((int16_t)d) << 16;
+
+ fp16 = double_to_fp1616(d);
+ re = fp1616_to_double(fp16);
+
+ /* printf("FP16: double: %f fp16: %u int: %u frac: %u re:%f\n", d, fp16, integral, frac, re); */
+
+ assert((fp16 & 0xFFFF0000) == integral);
+ assert((fp16 & 0x0000FFFF) == frac);
+
+ re = fp1616_to_double(fp16);
+ /* since we lose precision, we only do rough range testing */
+ assert(re > d - 0.1);
+ assert(re < d + 0.1);
+
+}
+
+static void
+_test_double_fp32_values(double d)
+{
+ FP3232 fp32;
+ double re;
+ uint32_t frac;
+ int32_t integral;
+
+ if (d > 0x7FFFFFFF) {
+ printf("Test out of range\n");
+ assert(0);
+ }
+
+ frac = rint(trunc(ldexp(d - trunc(d), 32)));
+ integral = ((int32_t)d);
+
+ fp32 = double_to_fp3232(d);
+ re = fp3232_to_double(fp32);
+
+ /* printf("FP32: double: %f fp32: %u.%u int: %u frac: %u re:%f\n", d, fp32.integral, fp32.frac, integral, frac, re); */
+
+ assert(fp32.integral == integral);
+ assert(fp32.frac == frac);
+
+ re = fp3232_to_double(fp32);
+ /* since we lose precision, we only do rough range testing */
+ assert(re > d - 0.1);
+ assert(re < d + 0.1);
+}
+
+static void
+dix_double_fp_conversion(void)
+{
+ long i;
+ printf("Testing double to FP1616/FP3232 conversions\n");
+
+ _test_double_fp16_values(0);
+ for (i = 1; i < 0x7FFF; i <<= 1) {
+ double val;
+
+ val = i;
+ _test_double_fp16_values(val);
+ _test_double_fp32_values(val);
+
+ /* and some pseudo-random floating points */
+ val = i + 0.00382;
+ _test_double_fp16_values(val);
+ _test_double_fp32_values(val);
+
+ val = i + 0.05234;
+ _test_double_fp16_values(val);
+ _test_double_fp32_values(val);
+
+ val = i + 0.12342;
+ _test_double_fp16_values(val);
+ _test_double_fp32_values(val);
+
+ val = i + 0.27583;
+ _test_double_fp16_values(val);
+ _test_double_fp32_values(val);
+
+ val = i + 0.50535;
+ _test_double_fp16_values(val);
+ _test_double_fp32_values(val);
+
+ val = i + 0.72342;
+ _test_double_fp16_values(val);
+ _test_double_fp32_values(val);
+
+ val = i + 0.80408;
+ _test_double_fp16_values(val);
+ _test_double_fp32_values(val);
+ }
+
+ for (i = 0x7FFFF; i < 0x7FFFFFFF; i <<= 1) {
+ _test_double_fp32_values(i);
+ /* and a few more random floating points, obtained
+ * by faceplanting into the numpad repeatedly */
+ _test_double_fp32_values(i + 0.010177);
+ _test_double_fp32_values(i + 0.213841);
+ _test_double_fp32_values(i + 0.348720);
+ _test_double_fp32_values(i + 0.472020);
+ _test_double_fp32_values(i + 0.572020);
+ _test_double_fp32_values(i + 0.892929);
+ }
+
+}
+
int main(int argc, char** argv)
{
+ dix_double_fp_conversion();
dix_input_valuator_masks();
dix_input_attributes();
dix_init_valuators();
--
1.7.6.4
More information about the xorg-devel
mailing list