[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