[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