utils: Fix GMP scaling unit test

GMP only uses "unsigned long int", which is 32 bit
on 32 bit architectures and can't hold a guint64.
This resulted in false unit test failures on 32 bit architectures.

Fixes bug #595133.
This commit is contained in:
Sebastian Dröge 2009-09-15 09:41:28 +02:00
parent ebe095420a
commit 7464062ff2

View file

@ -774,32 +774,84 @@ enum round_t
ROUND_DOWN ROUND_DOWN
}; };
static void
gmp_set_uint64 (mpz_t mp, guint64 x)
{
mpz_t two_32, tmp;
mpz_init (two_32);
mpz_init (tmp);
mpz_ui_pow_ui (two_32, 2, 32);
mpz_set_ui (mp, (unsigned long) ((x >> 32) & G_MAXUINT32));
mpz_mul (tmp, mp, two_32);
mpz_add_ui (mp, tmp, (unsigned long) (x & G_MAXUINT32));
mpz_clear (two_32);
mpz_clear (tmp);
}
static guint64
gmp_get_uint64 (mpz_t mp)
{
mpz_t two_64, two_32, tmp;
guint64 ret;
mpz_init (two_64);
mpz_init (two_32);
mpz_init (tmp);
mpz_ui_pow_ui (two_64, 2, 64);
mpz_ui_pow_ui (two_32, 2, 32);
if (mpz_cmp (tmp, two_64) >= 0)
return G_MAXUINT64;
mpz_clear (two_64);
mpz_tdiv_q (tmp, mp, two_32);
ret = mpz_get_ui (tmp);
ret <<= 32;
ret |= mpz_get_ui (mp);
mpz_clear (two_32);
mpz_clear (tmp);
return ret;
}
static guint64 static guint64
gmp_scale (guint64 x, guint64 a, guint64 b, enum round_t mode) gmp_scale (guint64 x, guint64 a, guint64 b, enum round_t mode)
{ {
mpz_t mp1, mp2; mpz_t mp1, mp2, mp3;
if (!b) if (!b)
/* overflow */ /* overflow */
return G_MAXUINT64; return G_MAXUINT64;
mpz_init_set_ui (mp1, x); mpz_init (mp1);
mpz_init (mp2); mpz_init (mp2);
mpz_mul_ui (mp2, mp1, a); mpz_init (mp3);
gmp_set_uint64 (mp1, x);
gmp_set_uint64 (mp3, a);
mpz_mul (mp2, mp1, mp3);
switch (mode) { switch (mode) {
case ROUND_TONEAREST: case ROUND_TONEAREST:
mpz_add_ui (mp1, mp2, b / 2); gmp_set_uint64 (mp1, b);
mpz_tdiv_q_ui (mp3, mp1, 2);
mpz_add (mp1, mp2, mp3);
mpz_set (mp2, mp1); mpz_set (mp2, mp1);
break; break;
case ROUND_UP: case ROUND_UP:
mpz_add_ui (mp1, mp2, b - 1); gmp_set_uint64 (mp1, b);
mpz_sub_ui (mp3, mp1, 1);
mpz_add (mp1, mp2, mp3);
mpz_set (mp2, mp1); mpz_set (mp2, mp1);
break; break;
case ROUND_DOWN: case ROUND_DOWN:
break; break;
} }
mpz_tdiv_q_ui (mp1, mp2, b); gmp_set_uint64 (mp3, b);
x = mpz_get_ui (mp1); mpz_tdiv_q (mp1, mp2, mp3);
x = gmp_get_uint64 (mp1);
mpz_clear (mp1); mpz_clear (mp1);
mpz_clear (mp2); mpz_clear (mp2);
mpz_clear (mp3);
return x; return x;
} }