Better bignum support for number->string

This commit is contained in:
Justin Ethier 2017-02-17 12:15:04 +00:00
parent 53a9e2613f
commit 46c41be356

View file

@ -1691,7 +1691,7 @@ char *int_to_binary(char *b, int x)
object Cyc_number2string2(void *data, object cont, int argc, object n, ...) object Cyc_number2string2(void *data, object cont, int argc, object n, ...)
{ {
object base = NULL; object base = NULL;
int base_num = 10, val; int base_num = 10, val, sz;
char buffer[1024]; char buffer[1024];
va_list ap; va_list ap;
va_start(ap, n); va_start(ap, n);
@ -1705,38 +1705,42 @@ object Cyc_number2string2(void *data, object cont, int argc, object n, ...)
base_num = unbox_number(base); base_num = unbox_number(base);
} }
if (base_num == 2) { if (is_object_type(n) && type_of(n) == bignum_tag) {
val = obj_is_int(n) ? if (base_num > 64 || base_num < 2) {
obj_obj2int(n) : Cyc_rt_raise2(data, "number->string - invalid radix for bignum", base);
type_of(n) == integer_tag ? integer_value(n) : ((int)double_value(n)); }
int_to_binary(buffer, val); mp_radix_size(&bignum_value(n), base_num, &sz);
} else if (base_num == 8) { if (sz > 1024) {
val = obj_is_int(n) ? // TODO: just temporary, need to handle this better
obj_obj2int(n) : Cyc_rt_raise2(data, "number->string - bignum is too large to convert", n);
type_of(n) == integer_tag ? integer_value(n) : ((int)double_value(n)); }
snprintf(buffer, 1024, "%o", val); mp_toradix(&bignum_value(n), buffer, base_num);
} else if (base_num == 16) {
val = obj_is_int(n) ?
obj_obj2int(n) :
type_of(n) == integer_tag ? integer_value(n) : ((int)double_value(n));
snprintf(buffer, 1024, "%X", val);
} else { } else {
if (obj_is_int(n)) { if (base_num == 2) {
snprintf(buffer, 1024, "%ld", obj_obj2int(n)); val = obj_is_int(n) ?
} else if (type_of(n) == integer_tag) { obj_obj2int(n) :
snprintf(buffer, 1024, "%d", ((integer_type *) n)->value); type_of(n) == integer_tag ? integer_value(n) : ((int)double_value(n));
} else if (type_of(n) == double_tag) { int_to_binary(buffer, val);
double2buffer(buffer, 1024, ((double_type *) n)->value); } else if (base_num == 8) {
} else if (type_of(n) == bignum_tag) { val = obj_is_int(n) ?
int sz; obj_obj2int(n) :
mp_radix_size(&bignum_value(n), 10, &sz); type_of(n) == integer_tag ? integer_value(n) : ((int)double_value(n));
if (sz > 1024) { snprintf(buffer, 1024, "%o", val);
// TODO: just temporary, need to handle this better } else if (base_num == 16) {
Cyc_rt_raise(data, "number->string - bignum is too large to print"); val = obj_is_int(n) ?
} obj_obj2int(n) :
mp_toradix(&bignum_value(n), buffer, 10); type_of(n) == integer_tag ? integer_value(n) : ((int)double_value(n));
snprintf(buffer, 1024, "%X", val);
} else { } else {
Cyc_rt_raise2(data, "number->string - Unexpected object", n); if (obj_is_int(n)) {
snprintf(buffer, 1024, "%ld", obj_obj2int(n));
} else if (type_of(n) == integer_tag) {
snprintf(buffer, 1024, "%d", ((integer_type *) n)->value);
} else if (type_of(n) == double_tag) {
double2buffer(buffer, 1024, ((double_type *) n)->value);
} else {
Cyc_rt_raise2(data, "number->string - Unexpected object", n);
}
} }
} }
make_string(str, buffer); make_string(str, buffer);