[cairo] Cairo/pixman behavior with large translations
Siarhei Siamashka
siarhei.siamashka at gmail.com
Thu Dec 6 06:09:40 PST 2012
On Thu, 06 Dec 2012 14:02:11 +0100
sandmann at cs.au.dk (Søren Sandmann) wrote:
> Søren Sandmann <sandmann at cs.au.dk> writes:
>
> > Intermediate results from matrix and vector multiplications fit in 64
> > bits, and
>
> That is, as long as the final result doesn't overflow the 31.16 type,
> the intermediate values fit in 64 bits.
We are fine if we don't mind dealing with two intermediate 64-bit
variables for doing multiplication and accumulation ('lo' and 'hi'
variables in the example below):
/*******************************************************************/
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
/* a reference implementation (needs 128-bit int types) */
static uint64_t
ref_mul_16_16_by_31_16_to_48_16 (int32_t fix_16_16, int64_t fix_31_16)
{
return ((__int128_t)fix_16_16 * fix_31_16 + 0x8000) >> 16;
}
/* this is a reference floating point implementation for comparison */
static __float128
float_mul_16_16_by_31_16_to_48_16 (int32_t fix_16_16, int64_t fix_31_16)
{
__float128 a = (__float128)fix_16_16 / 65536.;
__float128 b = (__float128)fix_31_16 / 65536.;
return a * b;
}
/* this implementation does not need 128-bit data types */
static uint64_t
mul_16_16_by_31_16_to_48_16 (int32_t fix_16_16, int64_t fix_31_16)
{
int64_t hi = (int64_t)fix_16_16 * (fix_31_16 >> 16);
int64_t lo = (int64_t)fix_16_16 * (fix_31_16 & 0xFFFF);
return hi + ((lo + 0x8000) >> 16);
}
void fillrand (void *p, int size)
{
uint8_t *bytep = (uint8_t *)p;
while (size--)
*bytep++ = rand() & 0xFF;
}
int main (void)
{
int i;
for (i = 0; i < 100000000; i++)
{
int32_t fix_16_16;
int64_t fix_31_16;
int64_t ref_res, res;
__float128 float_res; /* 64-bit double data type is not enough */
fillrand (&fix_16_16, sizeof(fix_16_16));
fillrand (&fix_31_16, sizeof(fix_31_16));
/* in fact this will be 33.16 random number after this shift,
* but in the matrix by vector multiplication code we want to
* be able to add together 3 multiplication results without
* overflow, hence the fixed 31.16 data type is interesting
* for the extra 2 bits headroom */
fix_31_16 >>= 15;
/* test the correctness of mul_16_16_by_31_16_to_48_16 by comparing
* it with the other implementations */
ref_res = ref_mul_16_16_by_31_16_to_48_16 (fix_16_16, fix_31_16);
float_res = float_mul_16_16_by_31_16_to_48_16 (fix_16_16, fix_31_16);
res = mul_16_16_by_31_16_to_48_16 (fix_16_16, fix_31_16);
assert(ref_res == res);
assert(fabs(float_res * 65536. - (__float128)res) < 0.51);
}
return 0;
}
/*******************************************************************/
--
Best regards,
Siarhei Siamashka
More information about the cairo
mailing list