CONVERSIONS notation: typedef unsigned int uint; typedef unsigned long ulong; destination: source int: int, long, uint, ulong, ZZ, float, double, xdouble, quad_float, RR GF2, zz_p, ZZ_p long: int, long, uint, ulong, ZZ, float, double, xdouble, quad_float, RR GF2, zz_p, ZZ_p uint: int, long, uint, ulong, ZZ, float, double, xdouble, quad_float, RR GF2, zz_p, ZZ_p ulong: int, long, uint, ulong, ZZ, float, double, xdouble, quad_float, RR GF2, zz_p, ZZ_p ZZ: int, long, uint, ulong, ZZ, float, double, xdouble, quad_float, RR GF2, zz_p, ZZ_p float: int, long, uint, ulong, ZZ, float, double, xdouble, quad_float, RR double: int, long, uint, ulong, ZZ, float, double, xdouble, quad_float, RR xdouble: int, long, uint, ulong, ZZ, float, double, xdouble, RR quad_float: int, long, uint, ulong, ZZ, float, double, quad_float, RR RR: int, long, uint, ulong, ZZ, float, double, xdouble, quad_float, RR ZZ_p: long, ZZ, ZZ_p ZZ_pX: long, ZZ, ZZ_p; ZZX, ZZ_pX; ZZ_pE; vec_ZZ_p zz_p: long, ZZ, zz_p zz_pX: long, ZZ, zz_p; ZZX, zz_pX; zz_pE; vec_zz_p ZZX: long, ZZ; ZZX, GF2X, zz_pX, ZZ_pX; vec_ZZ GF2: long, ZZ, GF2 GF2X: long, ZZ, GF2; ZZX, GF2X; GF2E; vec_GF2 GF2E: long, ZZ, GF2, GF2E; GF2X GF2EX: long, ZZ, GF2, GF2E; ZZX, GF2X, GF2EX; vec_GF2E ZZ_pE: long, ZZ, ZZ_p, ZZ_pE; ZZ_pX ZZ_pEX: long, ZZ, ZZ_p, ZZ_pE; ZZX, ZZ_pX, ZZ_pEX; vec_ZZ_pE zz_pE: long, ZZ, zz_p, zz_pE; zz_pX zz_pEX: long, ZZ, zz_p, zz_pE; ZZX, zz_pX, zz_pEX; vec_zz_pE vec_ZZ: ZZX vec_ZZ_p: ZZ_pX vec_zz_p: zz_pX vec_GF2: GF2X vec_ZZ_pE: ZZ_pEX vec_zz_pE: zz_pEX vec_GF2E: GF2EX ********** NOTES *********** nomenclature: - integral types: int, long, uint, ulong, ZZ - bounded integral types: int, long, uint, ulong - floating point types: float, double, xdouble, quad_float, RR [1] All conversion operators come in procedural or functional form. To convert a of type S to x of type T, you can write conv(x, a); or x = conv(a); E.g., conv(a), conv(a), conv< Vec >, etc. The notation conv(a) was introduced in NTL v6. Prior to this, the notation to_T(a) was used. For backard compatibility, the various "to_T" functions have been retained; however, their use is dicouraged. Also note that new conversions have been added in v6 for which there is no corresponding "to_T" function: for these, one must use the new "conv" notation. Note that conv is implemented as a template function: template T conv(const S& a) { T x; conv(x, a); return x; } Thus, the call conv(a) always resolves to the procedure call conv(x, a). Modern C++ compilers do a pretty good job implementing the "named return value optimization", so this should not create too any unnecessary temporary objects. [2] In addition to the conversions listed, there is a generic conversion from a C-strings (i.e., const char *) to any type T, which is implemented using templates using the input operator >> for type T. So, for example, you can write ZZ x = conv("99999999999999999999999"); Vec v; conv(v, "[1 2 3]"); If the input fails, the conversion operation will raise an error. [3] In addition to the conversions listed, for generic vector types, a template conversion operator is provided: template void conv(Vec& x, const Vec& a) { long n = a.length(); x.SetLength(n); for (long i = 0; i < n; i++) conv(x[i], a[i]); } This provides component-wise conversion. This, if there is a conversion provided from S to T, then there is automatically a conversion provided from Vec to Vec. Note that because of the simple implementation, this input a is not allowed to alias any components of the output x. However, a and x could be the same. Similarly, for generic matrix types Mat, a template conversion operator provides component-wise conversion. Again, the input may not alias the output. [4] All conversions from an integral type to a bounded integral type compute the result modulo 2^n, where n is the number of bits of the destination type: no overflow occurs. [5] All floating point to signed integral conversions compute the floor function *exactly*, unless the destination type is int or long and overflow occurs, in which case the result is undefined. An exception: converting an RR x to int or long will always yield floor(x) modulo 2^n, where n is the number of bits in the destination type. [6] Conversions from floating point to unsigned int and unsigned long are done via conversions to signed long: if the conversion to long overflows, the result is undefined; otherwise, the result is computed modulo 2^n, where n is the number of bits in the destination type. [7] The ZZ to double conversion routine is very precise: the result is the nearest double, breaking ties using the "round to even" rule. Overflow results in +/- Infinity. All this assumes the underlying floating point adheres to the IEEE standard. [8] All conversions to RR round to the current working precision: even converting an RR to an RR. [9] All conversions from long or ZZ to one of the "mod p" types ZZ_p, ZZ_pX, ZZ_pE, ZZ_pEX, zz_p, zz_pX, zz_pE, zz_pEX, GF2, GF2X, GF2E, GF2EX yield the the residue class modulo p (or 2). [10] All polynomial-to-polynomial conversions apply coefficient-wise conversion. Note that as a rule, if a conversion S to T is provided, then there is a corresponding conversion from the polynomial ring S[X] to the polynomial ring T[X]. [11] All polynomial/vector conversions simply copy from/to the coefficient vector of the polynomial. [12] The GF2X/ZZ_pX/zz_pX to GF2E/ZZ_pE/zz_pE conversions reduce the given polynomial modulo the current modulus; the reverse conversions yield the standard representative (smallest degree polynomial). [13] Conversions from GF2, zz_p or ZZ_p to any integral type yeld the standard representative (least non-negative) of the given residue class.