[PATCH] dix: add utility functions for double to/fro FP1616/FP3232 conversion
Peter Hutterer
peter.hutterer at who-t.net
Tue Oct 4 18:12:01 PDT 2011
On Tue, Oct 04, 2011 at 06:02:21PM -0700, Jeremy Huddleston wrote:
> 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"
I thought it was quite expressive as-is but I will amend :)
I wonder if we need this path at all though. after all, if d-trunc(d) starts
giving us values outside of 0..1 we have other problems.
Also, this needs a follow-up patch anyway, I completely forgot to test
negative numbers.
Cheers,
Peter
> 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