diff --git a/src/ops/nqp_bigint.ops b/src/ops/nqp_bigint.ops index 60267f3629..50a87d66c8 100644 --- a/src/ops/nqp_bigint.ops +++ b/src/ops/nqp_bigint.ops @@ -54,26 +54,38 @@ static void from_num(FLOATVAL d, mp_int *a) { FLOATVAL da = fabs(d); FLOATVAL upper; FLOATVAL lower; + FLOATVAL lowest; + FLOATVAL rest; int digits = 0; mp_zero(a); - while (da > d_digit * d_digit) {; + while (da > d_digit * d_digit * d_digit) {; da /= d_digit; digits++; } - mp_grow(a, digits + 2); + mp_grow(a, digits + 3); - /* populate the top 2 digits */ - upper = da / d_digit; - lower = fmod(da, d_digit); + /* populate the top 3 digits */ + upper = da / (d_digit*d_digit); + rest = fmod(da, d_digit*d_digit); + lower = rest / d_digit; + lowest = fmod(rest,d_digit ); if (upper >= 1) { mp_set_long(a, (unsigned long) upper); mp_mul_2d(a, DIGIT_BIT , a); + DIGIT(a, 0) = (mp_digit) lower; + mp_mul_2d(a, DIGIT_BIT , a); } else { - a->used = 1; + if (lower >= 1) { + mp_set_long(a, (unsigned long) lower); + mp_mul_2d(a, DIGIT_BIT , a); + a->used = 2; + } else { + a->used = 1; + } } - DIGIT(a, 0) = (mp_digit) lower; + DIGIT(a, 0) = (mp_digit) lowest; /* shift the rest */ mp_mul_2d(a, DIGIT_BIT * digits, a); diff --git a/t/nqp/60-bigint.t b/t/nqp/60-bigint.t index 3ba08df395..f369313cd9 100644 --- a/t/nqp/60-bigint.t +++ b/t/nqp/60-bigint.t @@ -1,7 +1,7 @@ #! nqp use nqpmo; -plan(34); +plan(36); my $knowhow := pir::get_knowhow__P(); my $bi_type := $knowhow.new_type(:name('TestBigInt'), :repr('P6bigint')); @@ -80,6 +80,12 @@ ok(nqp::abs_n($big - $converted) / $big < 1e-4, 'bigint -> float, 1e16'); my $float := 123456789e240; ok(nqp::iseq_n($float, nqp::tonum_I(nqp::fromnum_I($float, $bi_type))), 'to_num and from_num round-trip'); +my $small_float := 1e3; +ok(nqp::iseq_n($small_float, nqp::tonum_I(nqp::fromnum_I($small_float, $bi_type))), + 'to_num and from_num round-trip on small floats'); +my $medium_float := 1e14; +ok(nqp::iseq_n($medium_float, nqp::tonum_I(nqp::fromnum_I($medium_float, $bi_type))), + 'to_num and from_num round-trip on medium sized floats'); $float := -$float; ok(nqp::iseq_n($float, nqp::tonum_I(nqp::fromnum_I($float, $bi_type))), 'to_num and from_num round-trip (negative number)');