diff --git a/docs/NEWS.md b/docs/NEWS.md index 974fd75..60699fd 100644 --- a/docs/NEWS.md +++ b/docs/NEWS.md @@ -3,6 +3,7 @@ * *feature:* new **--bar-style** option to change the default bar style ([#15](https://codeberg.org/a-j-wood/pv/issues/15)) * *feature:* new bar formats "**%{bar-plain}**", "**%{bar-block}**", "**%{bar-granular}**", "**%{bar-shaded}**" ([#15](https://codeberg.org/a-j-wood/pv/issues/15)) * *feature:* allow decimal values such as "1.5G" with "**--size**", "**--rate-limit**", "**--buffer-size**", and "**error-skip-block**" ([#35](https://codeberg.org/a-j-wood/pv/issues/35)) + * *cleanup:* track transfer percentage as a floating point value for better precision (and rounding) * *docs:* simplified the synopsis section of the manual ### 1.9.15 - 8 December 2024 diff --git a/src/include/pv-internal.h b/src/include/pv-internal.h index 9ad0062..40fb3e8 100644 --- a/src/include/pv-internal.h +++ b/src/include/pv-internal.h @@ -310,7 +310,7 @@ struct pvstate_s { off_t prev_transferred; /* total amount transferred when called last time */ - int percentage; /* transfer percentage completion */ + double percentage; /* transfer percentage completion */ } calc; /******************** diff --git a/src/include/pv.h b/src/include/pv.h index 2aea91a..a4da584 100644 --- a/src/include/pv.h +++ b/src/include/pv.h @@ -86,11 +86,11 @@ extern unsigned int pv_getnum_count(const char *, bool); extern bool pv_getnum_check(const char *, pv_numtype); /* - * Return an integer representing the first amount as a percentage of the + * Return a value representing the first amount as a percentage of the * second total, i.e. 100*amount/total. If the second value, the total, is * zero or less, return 0. */ -extern int pv_percentage(off_t, const off_t); +extern double pv_percentage(off_t, const off_t); /* * String handling wrappers. diff --git a/src/pv/calc.c b/src/pv/calc.c index cac291e..e7bc377 100644 --- a/src/pv/calc.c +++ b/src/pv/calc.c @@ -164,8 +164,8 @@ void pv_calculate_transfer_rate(pvstate_t state, bool final) } /* Ensure the percentage is never negative or huge. */ - if (state->calc.percentage < 0) - state->calc.percentage = 0; - if (state->calc.percentage > 100000) - state->calc.percentage = 100000; + if (state->calc.percentage < 0.0) + state->calc.percentage = 0.0; + if (state->calc.percentage > 100000.0) + state->calc.percentage = 100000.0; } diff --git a/src/pv/display.c b/src/pv/display.c index 96bd016..889262c 100644 --- a/src/pv/display.c +++ b/src/pv/display.c @@ -515,7 +515,7 @@ static bool pv__format_numeric(pvstate_t state, pvdisplay_t display) msg_percent[0] = '\0'; if (show_percentage) { (void) pv_snprintf(msg_percent, sizeof(msg_percent), - "%s%d", first_item ? "" : " ", state->calc.percentage); + "%s%.0f", first_item ? "" : " ", state->calc.percentage); first_item = false; } diff --git a/src/pv/format/bufferpercent.c b/src/pv/format/bufferpercent.c index 7eb80c9..4bb4db6 100644 --- a/src/pv/format/bufferpercent.c +++ b/src/pv/format/bufferpercent.c @@ -24,12 +24,12 @@ size_t pv_formatter_buffer_percent(pvformatter_args_t args) return 0; if (args->state->transfer.buffer_size > 0) { - int pct_used = pv_percentage((off_t) - (args->state->transfer.read_position - - args->state->transfer.write_position), - (off_t) - (args->state->transfer.buffer_size)); - (void) pv_snprintf(content, sizeof(content), "{%3d%%}", pct_used); + double pct_used = pv_percentage((off_t) + (args->state->transfer.read_position - + args->state->transfer.write_position), + (off_t) + (args->state->transfer.buffer_size)); + (void) pv_snprintf(content, sizeof(content), "{%3.0f%%}", pct_used); } #ifdef HAVE_SPLICE if (args->state->transfer.splice_used) diff --git a/src/pv/format/progressbar.c b/src/pv/format/progressbar.c index 8b94ef2..4249138 100644 --- a/src/pv/format/progressbar.c +++ b/src/pv/format/progressbar.c @@ -132,8 +132,8 @@ static size_t pv_formatter_progress_knownsize(pvformatter_args_t args, char *buf if (has_tip && filled_bar_width > 0) filled_bar_width -= style->tip.width; - debug("width=%d bar_area_width=%d filled_bar_width=%d after_bar_width=%d", args->segment->width, bar_area_width, - filled_bar_width, after_bar_width); + debug("percentage=%.2f width=%d bar_area_width=%d filled_bar_width=%d after_bar_width=%d", bar_percentage, + args->segment->width, bar_area_width, filled_bar_width, after_bar_width); buffer_offset = 0; diff --git a/src/pv/number.c b/src/pv/number.c index fb191fc..5e9915f 100644 --- a/src/pv/number.c +++ b/src/pv/number.c @@ -285,16 +285,20 @@ bool pv_getnum_check(const char *str, pv_numtype type) /* - * Return an integer representing "amount" as a percentage of "total", i.e. + * Return a value representing "amount" as a percentage of "total", i.e. * 100*amount/total. If "total" is zero or less, return 0. */ -int pv_percentage(off_t amount, const off_t total) +double pv_percentage(off_t amount, const off_t total) { + double amount_as_double; + if (total < 1) - return 0; + return 0.0; - amount *= 100; - amount /= total; + amount_as_double = (double) amount; - return (int) amount; + amount_as_double *= 100.0; + amount_as_double /= (double) total; + + return amount_as_double; } diff --git a/src/pv/state.c b/src/pv/state.c index 051d95e..4f76fd7 100644 --- a/src/pv/state.c +++ b/src/pv/state.c @@ -80,7 +80,7 @@ void pv_state_reset(pvstate_t state) state->calc.ratesquared_sum = 0.0; state->calc.measurements_taken = 0; state->calc.prev_transferred = 0; - state->calc.percentage = 0; + state->calc.percentage = 0.0; state->calc.history_first = state->calc.history_last = 0; if (NULL != state->calc.history) { state->calc.history[0].elapsed_sec = 0.0;