I'm currently using the NTL library to store big integers (NTL::ZZ
). It looks like the only serialization way in lib is from ZZ
to std::string
(and std::string
to ZZ
for deserialization). But if I want to store and transfer a large number of integers, it becomes too slow. And the size of the transferred text is too large. Is there a better way to serialize and deserialize NTL::ZZ
? such as binary?
It is easy to miss, but ZZ provides conversions to and from byte sequences:
void ZZFromBytes(ZZ& x, const unsigned char *p, long n);
ZZ ZZFromBytes(const unsigned char *p, long n);
// x = sum(p[i]*256^i, i=0..n-1).
// NOTE: in the unusual event that a char is more than 8 bits,
// only the low order 8 bits of p[i] are used
void BytesFromZZ(unsigned char *p, const ZZ& a, long n);
// Computes p[0..n-1] such that abs(a) == sum(p[i]*256^i, i=0..n-1) mod 256^n.
long NumBytes(const ZZ& a);
long NumBytes(long a);
With simple length-prefix framing, you can thus have:
void writeZZ(ostream& os, const ZZ& a) {
long size = htobe32(NumBytes(a));
std::string buf(size, 0);
BytesFromZZ(buf.data(), a, buf.size());
os.write(&size, sizeof(long));
os.write(buf.data(), buf.size());
}
ZZ readZZ(istream& is) {
long size;
is.read(&size, sizeof(long));
size = be32toh(size);
std::string buf(size, 0);
is.read(buf.data(), size);
return ZZFromBytes(buf.data(), size);
}
This can obviously be improved with error checking and by using a single thread-local buf instead of creating a fresh one every time.