[PATCH v3] dix: add utility functions for double to/fro FP1616/FP3232 conversion

Peter Hutterer peter.hutterer at who-t.net
Wed Oct 5 15:37:24 PDT 2011


On Wed, Oct 05, 2011 at 03:02:52PM -0700, Jeremy Huddleston wrote:
> 
> Co-authored-by: Jeremy Huddleston <jeremyhu at apple.com>
> Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
> ---
> Attached is a self-contained version of this called test.c
> 
> Changes from v2:
> 1UUL instead of ldexp
> Cleanup to make style match in both cases
> Improved testing
> Fixed a bug with negatives

please put the printfs in comments, it ends up a bit noisy. 
> 
>  dix/inpututils.c     |   65 ++++++++++++++++++++++++++
>  include/inpututils.h |    6 ++
>  test/input.c         |  125 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 196 insertions(+), 0 deletions(-)
> 
> diff --git a/dix/inpututils.c b/dix/inpututils.c
> index 0a3d3d8..ed9dedd 100644
> --- a/dix/inpututils.c
> +++ b/dix/inpututils.c
> @@ -759,3 +759,68 @@ input_option_set_value(InputOption *opt, const char *value)
>      if (value)
>          opt->value = strdup(value);
>  }
> +
> +
> +/* FP1616/FP3232 conversion functions.
> + * Fixed point types are encoded as signed integral and unsigned frac. So any
> + * negative number -n.m is encoded as floor(n) + (1 - 0.m).
> + */
> +double
> +fp1616_to_double(FP1616 in)
> +{
> +    double ret;
> +    double frac;
> +
> +    ret = (double)(in >> 16);
> +    frac = ldexp((double)(in & 0xffff), -16);
> +    ret += frac;
> +    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 tmp;
> +    uint32_t frac_d;

if you make that a uint16_t, you shouldn't need the 0xffff further south.
but I guess it doesn't matter much.

Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>, thanks.


Cheers,
  Peter

> +
> +    tmp = floor(in);
> +    integral = (int32_t)tmp;
> +
> +    tmp = (in - integral) * (1ULL << 16); /* optimized from ldexp(in - integral, 16) */
> +    frac_d = (uint16_t)tmp;
> +
> +    ret = integral << 16;
> +    ret |= frac_d & 0xffff;
> +    return ret;
> +}
> +
> +FP3232
> +double_to_fp3232(double in)
> +{
> +    FP3232 ret;
> +    int32_t integral;
> +    double tmp;
> +    uint32_t frac_d;
> +
> +    tmp = floor(in);
> +    integral = (int32_t)tmp;
> +
> +    tmp = (in - integral) * (1ULL << 32); /* optimized from ldexp(in - integral, 32) */
> +    frac_d = (uint32_t)tmp;
> +
> +    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 afc4d4d..193362c 100644
> --- a/test/input.c
> +++ b/test/input.c
> @@ -1462,9 +1462,134 @@ static void input_option_test(void)
>      assert(list == NULL);
>  }
>  
> +static void
> +_test_double_fp16_values(double orig_d)
> +{
> +    FP1616 first_fp16, final_fp16;
> +    double final_d;
> +    char first_fp16_s[64];
> +    char final_fp16_s[64];
> +
> +    if (orig_d > 0x7FFF) {
> +        printf("Test out of range\n");
> +        assert(0);
> +    }
> +
> +    first_fp16 = double_to_fp1616(orig_d);
> +    final_d = fp1616_to_double(first_fp16);
> +    final_fp16 = double_to_fp1616(final_d);
> +
> +    snprintf(first_fp16_s, sizeof(first_fp16_s), "%d + %u * 2^-16", (first_fp16 & 0xffff0000) >> 16, first_fp16 & 0xffff);
> +    snprintf(final_fp16_s, sizeof(final_fp16_s), "%d + %u * 2^-16", (final_fp16 & 0xffff0000) >> 16, final_fp16 & 0xffff);
> +
> +    printf("FP16: original double: %f first fp16: %s, re-encoded double: %f, final fp16: %s\n", orig_d, first_fp16_s, final_d, final_fp16_s);
> +
> +    /* since we lose precision, we only do rough range testing */
> +    assert(final_d > orig_d - 0.1);
> +    assert(final_d < orig_d + 0.1);
> +
> +    assert(memcmp(&first_fp16, &final_fp16, sizeof(FP1616)) == 0);
> +
> +    if (orig_d > 0)
> +        _test_double_fp16_values(-orig_d);
> +}
> +
> +static void
> +_test_double_fp32_values(double orig_d)
> +{
> +    FP3232 first_fp32, final_fp32;
> +    double final_d;
> +    char first_fp32_s[64];
> +    char final_fp32_s[64];
> +
> +    if (orig_d > 0x7FFFFFFF) {
> +        printf("Test out of range\n");
> +        assert(0);
> +    }
> +
> +    first_fp32 = double_to_fp3232(orig_d);
> +    final_d = fp3232_to_double(first_fp32);
> +    final_fp32 = double_to_fp3232(final_d);
> +
> +    snprintf(first_fp32_s, sizeof(first_fp32_s), "%d + %u * 2^-32", first_fp32.integral, first_fp32.frac);
> +    snprintf(final_fp32_s, sizeof(final_fp32_s), "%d + %u * 2^-32", first_fp32.integral, final_fp32.frac);
> +
> +    printf("FP32: original double: %f first fp32: %s, re-encoded double: %f, final fp32: %s\n", orig_d, first_fp32_s, final_d, final_fp32_s);
> +
> +    /* since we lose precision, we only do rough range testing */
> +    assert(final_d > orig_d - 0.1);
> +    assert(final_d < orig_d + 0.1);
> +
> +    assert(memcmp(&first_fp32, &final_fp32, sizeof(FP3232)) == 0);
> +
> +    if (orig_d > 0)
> +        _test_double_fp32_values(-orig_d);
> +}
> +
> +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.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.1
> 
> 


More information about the xorg-devel mailing list