On Wed, Oct 05, 2011 at 03:02:52PM -0700, Jeremy Huddleston wrote: > > Co-authored-by: Jeremy Huddleston <jerem...@apple.com> > Signed-off-by: Peter Hutterer <peter.hutte...@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.hutte...@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 > > _______________________________________________ xorg-devel@lists.x.org: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel