diff --git a/lib/compat.c b/lib/compat.c index 513d79b2..2f7f79c1 100644 --- a/lib/compat.c +++ b/lib/compat.c @@ -181,26 +181,24 @@ char *do_big_num(int64 num, int human_flag, const char *fract) if (human_flag > 1) { int mult = human_flag == 2 ? 1000 : 1024; + if (num >= mult || num <= -mult) { - double dnum = (double)num / mult; - char units; - if (num < 0) - dnum = -dnum; - if (dnum < mult) - units = 'K'; - else if ((dnum /= mult) < mult) - units = 'M'; - else if ((dnum /= mult) < mult) - units = 'G'; - else if ((dnum /= mult) < mult) - units = 'T'; - else { - dnum /= mult; - units = 'P'; + const char* units = " KMGTPEZY"; + int64 powi = 1; + + for (;;) { + if (labs(num / mult) < powi) + break; + + if (units[1] == '\0') + break; + + powi *= mult; + ++units; } - if (num < 0) - dnum = -dnum; - snprintf(bufs[n], sizeof bufs[0], "%.2f%c", dnum, units); + + snprintf(bufs[n], sizeof bufs[0], "%.2f%c", + (double) num / powi, *units); return bufs[n]; } } diff --git a/rsync.1.md b/rsync.1.md index 2b4b7508..aeea1907 100644 --- a/rsync.1.md +++ b/rsync.1.md @@ -3326,9 +3326,9 @@ expand it. digits) by specifying the `--no-human-readable` (`--no-h`) option. The unit letters that are appended in levels 2 and 3 are: `K` (kilo), `M` - (mega), `G` (giga), `T` (tera), or `P` (peta). For example, a 1234567-byte - file would output as 1.23M in level-2 (assuming that a period is your local - decimal point). + (mega), `G` (giga), `T` (tera), `P` (peta), `E` (exa), `Z` (zetta) or `Y` + (yotta). For example, a 1234567-byte file would output as 1.23M in level-2 + (assuming that a period is your local decimal point). Backward compatibility note: versions of rsync prior to 3.1.0 do not support human-readable level 1, and they default to level 0. Thus,