Reviewed-by: Jeremy Huddleston <[email protected]> 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 <[email protected]> > Signed-off-by: Peter Hutterer <[email protected]> > --- > 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 > > _______________________________________________ > [email protected]: X.Org development > Archives: http://lists.x.org/archives/xorg-devel > Info: http://lists.x.org/mailman/listinfo/xorg-devel > _______________________________________________ [email protected]: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel
