diff --git a/releasenotes.md b/releasenotes.md index 27b9e8b06..fd24298f8 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -10,6 +10,7 @@ ### Fixes - Trying to cast an enum to int and back caused the compiler to crash. +- Incorrect rounding at compile time going from double to int. ### Stdlib changes - Hash functions for integer vectors and arrays. diff --git a/src/compiler/bigint.c b/src/compiler/bigint.c index 7fe9a636d..82efb1819 100644 --- a/src/compiler/bigint.c +++ b/src/compiler/bigint.c @@ -93,7 +93,7 @@ char *int_to_str(Int i, int radix, bool use_prefix) Int int_from_real(Real d, TypeKind type) { - return (Int){ type_kind_is_unsigned(type) ? i128_from_float_unsigned(d) : i128_from_float_signed(d), + return (Int){ type_kind_is_unsigned(type) ? i128_from_double_unsigned(d) : i128_from_double_signed(d), type }; } @@ -307,16 +307,6 @@ Int128 i128_lshr64(Int128 op1, uint64_t amount) } -Int128 i128_from_float_signed(Real d) -{ - return (Int128){ 0, (uint64_t)((int64_t)d) }; -} - -Int128 i128_from_float_unsigned(Real d) -{ - return (Int128){ 0, (uint64_t)d }; -} - UNUSED bool i128_get_bit(const Int128 *op, int bit) { ASSERT(bit < 128 && bit >= 0); @@ -922,7 +912,7 @@ UNUSED bool i128_can_convert_from_double_signed(double x) && x < ldexp(1, 127); } -UNUSED Int128 i128_from_double(double x) +Int128 i128_from_double_unsigned(double x) { if (x >= ldexp(1, 64)) { @@ -935,5 +925,5 @@ UNUSED Int128 i128_from_double(double x) UNUSED Int128 i128_from_double_signed(double x) { - return x < 0 ? i128_neg(i128_from_signed((int64_t)-x)) : i128_from_int((uint64_t)x); + return x < 0 ? i128_neg(i128_from_double_unsigned(-x)) : i128_from_double_unsigned(x); } diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index e05a842a4..56ec6a13d 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -2005,7 +2005,7 @@ Float float_neg(Float op); Float float_rem(Float op1, Float op2); Float float_from_string(const char *string, char **error); Float float_from_hex(const char *string, char **error); -Int128 i128_from_double(double x); +Int128 i128_from_double_unsigned(double x); bool int_ucomp(Int op1, uint64_t op2, BinaryOp op); bool int_icomp(Int op1, int64_t op2, BinaryOp op); bool int_comp(Int op1, Int op2, BinaryOp op); @@ -2035,7 +2035,7 @@ Int int_from_real(Real d, TypeKind type); char *int_to_str(Int i, int radix, bool use_prefix); bool i128_can_convert_from_double(double x); bool i128_can_convert_from_double_signed(double x); -Int128 i128_from_double(double x); +Int128 i128_from_double_unsigned(double x); Int128 i128_from_double_signed(double x); Int128 i128_extend(Int128 op, TypeKind type); Int128 i128_add(Int128 op1, Int128 op2); @@ -2075,8 +2075,6 @@ uint32_t i128_clz(const Int128 *op); uint32_t i128_ctz(const Int128 *op); UNUSED int i128_lsb(const Int128 *op); UNUSED int i128_msb(const Int128 *op); -Int128 i128_from_float_signed(Real d); -Int128 i128_from_float_unsigned(Real d); Int128 i128_from_signed(int64_t i); UNUSED Int128 i128_from_unsigned(uint64_t i); UNUSED bool i128_get_bit(const Int128 *op, int bit); diff --git a/test/unit/regression/float_compile_time_conversion.c3 b/test/unit/regression/float_compile_time_conversion.c3 new file mode 100644 index 000000000..ac168155b --- /dev/null +++ b/test/unit/regression/float_compile_time_conversion.c3 @@ -0,0 +1,14 @@ +module float_ct; + +fn void float_ct() @test +{ + var $input = 3e25; + var $temp = (int128)$input; + var $temp2 = (double)$temp; + test::eq_approx($temp2, 3e25); + + var $input2 = -3e25; + var $temp3 = (int128)$input2; + var $temp4 = (double)$temp3; + test::eq_approx($temp4, -3e25); +} \ No newline at end of file