You can have the quantized percentages to add to 100 but doing so will increase the quantization error compared with rounding. Doing so minimizes the aggregate error rather than the individual errors. While others have advocated minimizing the individual errors, there may be cases where minimizing the aggregate error is preferable.

The following example demonstrates one way the aggregate error can be minimized. The implementation is crude, not well tested and replete with print statements which may help you follow what it is doing.

use warnings; use strict; use Data::Dumper; my @percentages = generate(); print "@percentages\n"; my @quantized = quantize(1000,@percentages); print "Original percentages: @percentages\n"; print "Quantized percentages: @quantized\n"; my $sum; $sum += $_ foreach(@quantized);; print "Sum of quantized percentages: $sum\n"; =head2 my @quantized = quantize($factor, @percentages); The quantize() function takes a quantizaton factor and an array of percentages which should add to 100%. It returns an array of quantized percentages which does add to 100%. The percentages are quantized to multiples of (100/$factor). The function minimizes the worst case error. Two error functions are provided: one is the absolute error (the difference between the original value and the quantized value) and the other is the absolute relative error (the absolute error divided by the value being quantized). There are many other possibilities, depending on your needs. =cut sub quantize { my $quantum = 100 / shift; my $error = 0; my $sum = 0; my @x = map { my $q = sprintf("%0.0f", $_/$quantum) * $quantum; my $d = $q - $_; $error += $d; $sum += $q; [ $_, $q, $d ] } @_; print Dumper(\@x); print "initial total error: $error\n"; print "initial sum: $sum\n"; while(abs($sum - 100) > $quantum/2) { my $direction = ($sum > 100) ? 1 : -1 ; my $min_error = 10000; my $min_index = 0; print "errors of adjusted values: "; foreach my $i (0..(@x-1)) { my $e = abs($x[$i]->[2] - $quantum * $direction) / $x[$i]- +>[0]; # relative error #my $e = abs($x[$i]->[2] - $quantum * $direction); + # absolute error print " $e"; if($e < $min_error) { $min_error = $e; $min_index = $i; print "(i = $i)"; } } print "\n"; print "adjust $min_index: $x[$min_index]->[0], $x[$min_index]- +>[1] $x[$min_index]->[2]\n"; $x[$min_index]->[1] -= $quantum * $direction; $x[$min_index]->[2] -= $quantum * $direction; print "\t$x[$min_index]->[1], $x[$min_index]->[2]\n"; $sum -= $quantum * $direction; } return(map { $_->[1] } @x); } =head2 generate() The generate() function generates a somewhat random array of percentages that adds to 100%. =cut sub generate { my $sum = 0; my @percentages; foreach (1..20) { my $x = rand(50); if($sum + $x < 100) { push(@percentages, $x); $sum += $x; } } push(@percentages, 100 - $sum); return(@percentages); }

In reply to Re: accurately rounding numbers for percentages by ig
in thread accurately rounding numbers for percentages by derekn

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.