[PATCH] dix: add utility functions for double to/fro FP1616/FP3232 conversion
Jeremy Huddleston
jeremyhu at apple.com
Tue Oct 4 18:02:21 PDT 2011
Reviewed-by: Jeremy Huddleston <jeremyhu at apple.com>
Wow, that's all I missed? Not bad for coding in an email client ;)
You might want to replace my "crap" comment with something more descriptive such as "loss of precision, setting to 0"
On Oct 4, 2011, at 4:39 PM, Peter Hutterer wrote:
> 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
>
> _______________________________________________
> xorg-devel at lists.x.org: X.Org development
> Archives: http://lists.x.org/archives/xorg-devel
> Info: http://lists.x.org/mailman/listinfo/xorg-devel
>
More information about the xorg-devel
mailing list