#include "utils/relmapper.h"
  #include "utils/syscache.h"
  
 +/* Divide by two and round towards positive infinity. */
 +#define half_rounded(x)   (((x) + ((x) < 0 ? 0 : 1)) / 2)
  
  /* Return physical size of directory contents, or 0 if dir doesn't exist */
  static int64
      int64       limit = 10 * 1024;
     int64       limit2 = limit * 2 - 1;
  
 -   if (size < limit)
 +   if (Abs(size) < limit)
         snprintf(buf, sizeof(buf), INT64_FORMAT " bytes", size);
     else
     {
         size >>= 9;             /* keep one extra bit for rounding */
 -       if (size < limit2)
 +       if (Abs(size) < limit2)
             snprintf(buf, sizeof(buf), INT64_FORMAT " kB",
 -                    (size + 1) / 2);
 +                    half_rounded(size));
         else
         {
             size >>= 10;
 -           if (size < limit2)
 +           if (Abs(size) < limit2)
                 snprintf(buf, sizeof(buf), INT64_FORMAT " MB",
 -                        (size + 1) / 2);
 +                        half_rounded(size));
             else
             {
                 size >>= 10;
 -               if (size < limit2)
 +               if (Abs(size) < limit2)
                     snprintf(buf, sizeof(buf), INT64_FORMAT " GB",
 -                            (size + 1) / 2);
 +                            half_rounded(size));
                 else
                 {
                     size >>= 10;
                     snprintf(buf, sizeof(buf), INT64_FORMAT " TB",
 -                            (size + 1) / 2);
 +                            half_rounded(size));
                 }
             }
         }
   }
  
  static Numeric
 -numeric_plus_one_over_two(Numeric n)
 +numeric_absolute(Numeric n)
  {
     Datum       d = NumericGetDatum(n);
 +   Datum       result;
 +
 +   result = DirectFunctionCall1(numeric_abs, d);
 +   return DatumGetNumeric(result);
 +}
 +
 +static Numeric
 +numeric_half_rounded(Numeric n)
 +{
 +   Datum       d = NumericGetDatum(n);
 +   Datum       zero;
     Datum       one;
     Datum       two;
     Datum       result;
  
 +   zero = DirectFunctionCall1(int8_numeric, Int64GetDatum(0));
     one = DirectFunctionCall1(int8_numeric, Int64GetDatum(1));
     two = DirectFunctionCall1(int8_numeric, Int64GetDatum(2));
 -   result = DirectFunctionCall2(numeric_add, d, one);
 -   result = DirectFunctionCall2(numeric_div_trunc, result, two);
 +
 +   if (DatumGetBool(DirectFunctionCall2(numeric_ge, d, zero)))
 +       d = DirectFunctionCall2(numeric_add, d, one);
 +   else
 +       d = DirectFunctionCall2(numeric_sub, d, one);
 +
 +   result = DirectFunctionCall2(numeric_div_trunc, d, two);
     return DatumGetNumeric(result);
  }
  
      limit = int64_to_numeric(10 * 1024);
     limit2 = int64_to_numeric(10 * 1024 * 2 - 1);
  
 -   if (numeric_is_less(size, limit))
 +   if (numeric_is_less(numeric_absolute(size), limit))
     {
         result = psprintf("%s bytes", numeric_to_cstring(size));
     }
          /* size >>= 9 */
         size = numeric_shift_right(size, 9);
  
 -       if (numeric_is_less(size, limit2))
 +       if (numeric_is_less(numeric_absolute(size), limit2))
         {
 -           /* size = (size + 1) / 2 */
 -           size = numeric_plus_one_over_two(size);
 +           size = numeric_half_rounded(size);
             result = psprintf("%s kB", numeric_to_cstring(size));
         }
         else
         {
             /* size >>= 10 */
             size = numeric_shift_right(size, 10);
 -           if (numeric_is_less(size, limit2))
 +           if (numeric_is_less(numeric_absolute(size), limit2))
             {
 -               /* size = (size + 1) / 2 */
 -               size = numeric_plus_one_over_two(size);
 +               size = numeric_half_rounded(size);
                 result = psprintf("%s MB", numeric_to_cstring(size));
             }
             else
                  /* size >>= 10 */
                 size = numeric_shift_right(size, 10);
  
 -               if (numeric_is_less(size, limit2))
 +               if (numeric_is_less(numeric_absolute(size), limit2))
                 {
 -                   /* size = (size + 1) / 2 */
 -                   size = numeric_plus_one_over_two(size);
 +                   size = numeric_half_rounded(size);
                     result = psprintf("%s GB", numeric_to_cstring(size));
                 }
                 else
                 {
                     /* size >>= 10 */
                     size = numeric_shift_right(size, 10);
 -                   /* size = (size + 1) / 2 */
 -                   size = numeric_plus_one_over_two(size);
 +                   size = numeric_half_rounded(size);
                     result = psprintf("%s TB", numeric_to_cstring(size));
                 }
             }
      --- /dev/null
   +SELECT size, pg_size_pretty(size), pg_size_pretty(-1 * size) FROM
 +    (VALUES (10::bigint), (1000::bigint), (1000000::bigint),
 +            (1000000000::bigint), (1000000000000::bigint),
 +            (1000000000000000::bigint)) x(size);
 +       size       | pg_size_pretty | pg_size_pretty 
 +------------------+----------------+----------------
 +               10 | 10 bytes       | -10 bytes
 +             1000 | 1000 bytes     | -1000 bytes
 +          1000000 | 977 kB         | -977 kB
 +       1000000000 | 954 MB         | -954 MB
 +    1000000000000 | 931 GB         | -931 GB
 + 1000000000000000 | 909 TB         | -909 TB
 +(6 rows)
 +
 +SELECT size, pg_size_pretty(size), pg_size_pretty(-1 * size) FROM
 +    (VALUES (10::numeric), (1000::numeric), (1000000::numeric),
 +            (1000000000::numeric), (1000000000000::numeric),
 +            (1000000000000000::numeric),
 +            (10.5::numeric), (1000.5::numeric), (1000000.5::numeric),
 +            (1000000000.5::numeric), (1000000000000.5::numeric),
 +            (1000000000000000.5::numeric)) x(size);
 +        size        | pg_size_pretty | pg_size_pretty 
 +--------------------+----------------+----------------
 +                 10 | 10 bytes       | -10 bytes
 +               1000 | 1000 bytes     | -1000 bytes
 +            1000000 | 977 kB         | -977 kB
 +         1000000000 | 954 MB         | -954 MB
 +      1000000000000 | 931 GB         | -931 GB
 +   1000000000000000 | 909 TB         | -909 TB
 +               10.5 | 10.5 bytes     | -10.5 bytes
 +             1000.5 | 1000.5 bytes   | -1000.5 bytes
 +          1000000.5 | 977 kB         | -977 kB
 +       1000000000.5 | 954 MB         | -954 MB
 +    1000000000000.5 | 931 GB         | -931 GB
 + 1000000000000000.5 | 909 TB         | -909 TB
 +(12 rows)
 +
      --- /dev/null
   +SELECT size, pg_size_pretty(size), pg_size_pretty(-1 * size) FROM
 +    (VALUES (10::bigint), (1000::bigint), (1000000::bigint),
 +            (1000000000::bigint), (1000000000000::bigint),
 +            (1000000000000000::bigint)) x(size);
 +
 +SELECT size, pg_size_pretty(size), pg_size_pretty(-1 * size) FROM
 +    (VALUES (10::numeric), (1000::numeric), (1000000::numeric),
 +            (1000000000::numeric), (1000000000000::numeric),
 +            (1000000000000000::numeric),
 +            (10.5::numeric), (1000.5::numeric), (1000000.5::numeric),
 +            (1000000000.5::numeric), (1000000000000.5::numeric),
 +            (1000000000000000.5::numeric)) x(size);