Commit 1b5d61bee9

Andrew Kelley <superjoe30@gmail.com>
2017-08-18 04:52:12
fix bitCast for big integers
and make bigfloat use __float128
1 parent 2173e1f
Changed files (6)
src/bigfloat.cpp
@@ -11,7 +11,7 @@
 #include <math.h>
 #include <errno.h>
 
-void bigfloat_init_float(BigFloat *dest, long double x) {
+void bigfloat_init_float(BigFloat *dest, __float128 x) {
     dest->value = x;
 }
 
@@ -24,13 +24,13 @@ void bigfloat_init_bigint(BigFloat *dest, const BigInt *op) {
     if (op->digit_count == 0)
         return;
 
-    long double base = (long double)UINT64_MAX;
+    __float128 base = (__float128)UINT64_MAX;
     const uint64_t *digits = bigint_ptr(op);
 
     for (size_t i = op->digit_count - 1;;) {
         uint64_t digit = digits[i];
         dest->value *= base;
-        dest->value += (long double)digit;
+        dest->value += (__float128)digit;
 
         if (i == 0) {
             if (op->is_negative) {
@@ -96,7 +96,7 @@ void bigfloat_mod(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) {
 }
 
 void bigfloat_write_buf(Buf *buf, const BigFloat *op) {
-    buf_appendf(buf, "%Lf", op->value);
+    buf_appendf(buf, "%Lf", (long double)op->value);
 }
 
 Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2) {
@@ -117,6 +117,9 @@ void bigfloat_write_ieee597(const BigFloat *op, uint8_t *buf, size_t bit_count,
     } else if (bit_count == 64) {
         double f64 = op->value;
         memcpy(buf, &f64, 8);
+    } else if (bit_count == 128) {
+        __float128 f128 = op->value;
+        memcpy(buf, &f128, 16);
     } else {
         zig_unreachable();
     }
@@ -132,6 +135,10 @@ void bigfloat_read_ieee597(BigFloat *dest, const uint8_t *buf, size_t bit_count,
         double f64;
         memcpy(&f64, buf, 8);
         dest->value = f64;
+    } else if (bit_count == 128) {
+        __float128 f128;
+        memcpy(&f128, buf, 16);
+        dest->value = f128;
     } else {
         zig_unreachable();
     }
src/bigfloat.hpp
@@ -14,12 +14,12 @@
 #include <stddef.h>
 
 struct BigFloat {
-    long double value;
+    __float128 value;
 };
 
 struct Buf;
 
-void bigfloat_init_float(BigFloat *dest, long double x);
+void bigfloat_init_float(BigFloat *dest, __float128 x);
 void bigfloat_init_bigfloat(BigFloat *dest, const BigFloat *x);
 void bigfloat_init_bigint(BigFloat *dest, const BigInt *op);
 int bigfloat_init_buf_base10(BigFloat *dest, const uint8_t *buf_ptr, size_t buf_len);
src/bigint.cpp
@@ -220,6 +220,7 @@ void bigint_write_twos_complement(const BigInt *big_int, uint8_t *buf, size_t bi
     const uint64_t *twos_comp_digits = bigint_ptr(&twos_comp);
 
     size_t bits_in_last_digit = bit_count % 64;
+    if (bits_in_last_digit == 0) bits_in_last_digit = 64;
     size_t bytes_in_last_digit = (bits_in_last_digit + 7) / 8;
     size_t unwritten_byte_count = 8 - bytes_in_last_digit;
 
@@ -258,13 +259,13 @@ void bigint_write_twos_complement(const BigInt *big_int, uint8_t *buf, size_t bi
         for (size_t digit_index = 0; digit_index < digit_count; digit_index += 1) {
             uint64_t x = (digit_index < twos_comp.digit_count) ? twos_comp_digits[digit_index] : 0;
 
-            for (size_t byte_index = 0; byte_index < 8; byte_index += 1) {
+            for (size_t byte_index = 0;
+                byte_index < 8 && (digit_index + 1 < digit_count || byte_index < bytes_in_last_digit);
+                byte_index += 1)
+            {
                 uint8_t byte = x & 0xff;
                 buf[buf_index] = byte;
                 buf_index += 1;
-                if (buf_index >= unwritten_byte_count) {
-                    break;
-                }
                 x >>= 8;
             }
         }
std/special/compiler_rt/fixunstfsi_test.zig
@@ -0,0 +1,22 @@
+const __fixunstfsi = @import("fixunstfsi.zig").__fixunstfsi;
+const assert = @import("../../debug.zig").assert;
+
+fn test__fixunstfsi(a: f128, expected: u32) {
+    const x = __fixunstfsi(a);
+    assert(x == expected);
+}
+
+const inf128 = @bitCast(f128, u128(0x7fff0000000000000000000000000000));
+
+test "fixunstfsi" {
+    test__fixunstfsi(inf128, 0xffffffff);
+    test__fixunstfsi(0, 0x0);
+    test__fixunstfsi(0x1.23456789abcdefp+5, 0x24);
+    test__fixunstfsi(0x1.23456789abcdefp-3, 0x0);
+    test__fixunstfsi(0x1.23456789abcdefp+20, 0x123456);
+    test__fixunstfsi(0x1.23456789abcdefp+40, 0xffffffff);
+    test__fixunstfsi(0x1.23456789abcdefp+256, 0xffffffff);
+    test__fixunstfsi(-0x1.23456789abcdefp+3, 0x0);
+
+    test__fixunstfsi(0x1.p+32, 0xFFFFFFFF);
+}
std/special/compiler_rt/README.md
@@ -13,3 +13,12 @@ Any bugs should be solved by trying to duplicate the bug upstream.
  * If the bug only exists in Zig, something went wrong porting the code,
    and you can run the C code and Zig code side by side in a debugger
    to figure out what's happening differently.
+
+To test Zig's compiler-rt, run this command from the build directory:
+
+```
+make install && ./zig test ../std/special/compiler_rt/index.zig --library c
+```
+
+The `--library c` argument omits compiler-rt from the generated test program,
+which prevents duplicate symbol linker errors for all the compiler-rt builtins.
test/cases/cast.zig
@@ -258,3 +258,20 @@ test "explicit cast float number literal to integer if no fraction component" {
     const y = i32(f32(1e4));
     assert(y == 10000);
 }
+
+test "cast u128 to f128 and back" {
+    comptime testCast128();
+    testCast128();
+}
+
+fn testCast128() {
+    assert(cast128Int(cast128Float(0x7fff0000000000000000000000000000)) == 0x7fff0000000000000000000000000000);
+}
+
+fn cast128Int(x: f128) -> u128 {
+    @bitCast(u128, x)
+}
+
+fn cast128Float(x: u128) -> f128 {
+    @bitCast(f128, x)
+}