From 989ba059597d2f96da2072547f663351fd7fffe6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 21 Mar 2023 10:13:47 +0100 Subject: [PATCH] human-readable: calculate numbers in a loop This drops a lot of `else if` blocks and extends units by "E", "Z" & "Y". --- lib/compat.c | 34 ++++++++++++++++------------------ rsync.1.md | 6 +++--- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/lib/compat.c b/lib/compat.c index 513d79b23..2f7f79c1b 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 2b4b75087..aeea19074 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,