bug in gmp_fprintf?
Torbjörn Granlund
tg at gmplib.org
Mon Nov 23 22:35:28 UTC 2015
paul zimmermann <Paul.Zimmermann at inria.fr> writes:
Hi,
on https://gmplib.org/list-archives/gmp-discuss/2005-August/001787.html I read:
> "Support at the mpn and mpz levels for operands of up to 2^56 bits
> (on 64-bit machines). Current limits are: on 32-bit machines, 2^31 bits;
> on 64-bit machines, 2^37 bits".
However with the program below I get on a 64-bit machine:
zimmerma at tomate:/tmp$ ./a.out 8589934589
GMP version 6.1.0
P has 8589934589 bits
P has 1 bits
If I replace gmp_fprintf (fp, "%Zx\n", P) by mpz_out_str (fp, 16, P) I get:
zimmerma at tomate:/tmp$ ./a.out 8589934589
GMP version 6.1.0
P has 8589934589 bits
P has 8589934581 bits
Thanks, we'll look into this bug (or these bugs). Presumably some
32-bit counts have sneaked in somewhere in the conversion code.
In reproducing the error, I ran into embarrassingly slow code in
scanf/doscan.c; we read a byte at a time through a callback (see GET())
and test the base argument in a tight, serially dependent loop.
Clearly, the code should be replaced to something along these lines:
blk_size = 4; // initial input block size
cnt = 10; // count to next block size increase
while (...)
{
nread = fread (bp, 1, blk_size, fp);
if (nread != blk_size)
{
TODO: This does not mean we're hit the end of things; if we're
reading from a pipe we can get partial block reads. We should
probably simply loop around read, or fall back to getc. Note
that the code below expects an even # of bytes, padding/sentinel
would be needed for odd sizes.
}
c1 = map[bp[0]];
for (i = blk_size - 2; i != 0; i -= 2)
{
c2 = map[bp[1]];
if (c1 == 0)
goto end_of_string;
c1 = map[bp[2]];
if (c2 == 0)
goto end_of_string;
bp += 2;
}
c2 = map[bp[1]];
if (c1 == 0)
goto end_of_string;
if (c2 == 0)
goto end_of_string;
if (--cnt == 0)
{
blk_size = blk_size * 2;
cnt = 10;
if (blk_size > 1024)
cnt = MAX_ULONG; // stop increasing size
buf2 = realloc(buf, ...);
bp += buf2 - buf;
buf = buf2;
}
}
end_of_string:
while (...)
ungetc(bp[...], fp);
mp?_set_str (...);
Such code would be around 2 orders of magnitude faster than the present
code.
One could handle any base, and even floats and retionals by manipulating
map[] on-the-fly. (E.g., allow digits and '/' in the initial map[],
then patch map[] to make it allow just digits.
--
Torbjörn
Please encrypt, key id 0xC8601622
More information about the gmp-bugs
mailing list