github
Advanced Search
  • Home
  • Pricing and Signup
  • Explore GitHub
  • Blog
  • Login

semifor / math-round-fair

  • Admin
  • Watch Unwatch
  • Fork
  • Your Fork
  • Pull Request
  • Download Source
    • 1
    • 1
  • Source
  • Commits
  • Network (1)
  • Issues (0)
  • Downloads (1)
  • Wiki (1)
  • Graphs
  • Branch: master

click here to add a description

click here to add a homepage

  • Branches (1)
    • master ✓
  • Tags (1)
    • 0.01
Sending Request…
Enable Donations

Pledgie Donations

Once activated, we'll place the following badge in your repository's detail box:
Pledgie_example
This service is courtesy of Pledgie.

A perl module - Distribute rounding errors fairly — Read more

  cancel

  cancel
  • Private
  • Read-Only
  • HTTP Read-Only

This URL has Read+Write access

CPAN release 
semifor (author)
Sat Jul 04 20:10:46 -0700 2009
commit  f371ddf72c4692e40daf8fa63cd49da6afcd4dee
tree    6f64668a409daf14cb9549c18124d342502c05e7
parent  f19b5f89abe0a7329432a9925f790f3c45d474bb
math-round-fair /
name age
history
message
file .gitignore Loading commit data...
file Changes
file MANIFEST.SKIP
file Makefile.PL
file README
directory lib/
directory t/
README
NAME
    Math::Round::Fair - distribute rounding errors fairly

SYNOPSIS
      use Math::Round::Fair 'round_fair';

      my $cents = 7;
      my @weights = (1, 2, 3, 2, 1);
      my @allocation = round_fair($cents, @weights);

      print "@allocation\n";

      # output will be one of the following:
      # 0 1 3 2 1
      # 0 2 2 2 1
      # 0 2 3 1 1
      # 0 2 3 2 0
      # 1 1 2 2 1
      # 1 1 3 1 1
      # 1 1 3 2 0
      # 1 2 2 1 1
      # 1 2 2 2 0

      my @total;
      for ( 1..900 ) {
          @allocation = round_fair($cents, @weights);
          @total[$_] += @allocation[$_] for 0..$#allocation;
      }
      print "@total\n";

      # output will be *near* 700 1400 2100 1400 700, e.g.:
      # 698 1411 2096 1418 677

DESCRIPTION
    This module provides a single, exportable function, "round_fair", which
    allocates an integer value, fairly distributing rounding errors.

    "round_fair" rounds up, or down, randomly, where the probability of
    rounding up is equal to the fraction to round. For example, "round_fair"
    will round 0.5 to 1.0 with a probability of 0.5. It will round 0.3 to
    1.0 3 out of 10 times and to zero 7 out of 10 times, on average.

    Consider the problem of distributing one indivisible item, for example a
    penny, across three evenly weighted accounts, A, B, and C.

    Using a naive approach, none of the accounts will receive an allocation
    since the allocated portion to each is 1/3 and 1/3 rounds to zero. We
    are left with 1 unallocated item.

    Another approach is to adjust the basis at each step. We start with 1
    item to allocate to 3 accounts. 1/3 rounds to 0, so account A receives
    no allocation, and we drop it from consideration. Now, we have 2
    accounts and one item to allocate. 1/2 rounds to 1, so we allocate 1
    item to account B. Account C gets no allocation since there is nothing
    left to allocate.

    But what happens if we allocate one item to the same three accounts
    10,000 times? Ideally, two accounts should end up with 3,333 items and
    one should end up with 3,334 items.

    Using the naive approach, all three accounts receive no allocation since
    at each round the allocation is 1/3 which rounds to zero. Using the
    second method, account A and account C will receive no allocation, and
    account B will receive a total allocation of 10,000 items. Account B
    always receives the benefit of the rounding errors using the second
    method.

    "round_fair" uses an algorithm with randomness to ensure a fair
    distribution of rounding errors. In our example problem, we start with 1
    item to allocate. We calculate account A's share, 1/3. Since it is less
    than one item, we give it a 1/3 chance of rounding up (and, therefore, a
    2/3 chance of rounding down). It wins the allocation 1/3 of the time.
    2/3 of the time we continue to B. We calculate B's allocation as 1/2
    (since there are only 2 accounts remaining and one item to allocate). B
    rounds up 1/2 of 2/3 (or 1/3) of the time and down 1/2 of 2/3 (or 1/3)
    of the time. If neither A nor B rounds up (which occurs 2/3 * 1/2, or
    1/3 of the time), C's allocation is calculated as 1/1 since we have one
    item to allocate and only one account to allocate it to. So, 1/3 of the
    time C receives the benefit of the rounding error. We never end up with
    any unallocated items.

    This algorithm works for any number of weighted allocations.

    round_fair($value, @weights)
        Returns a list of integer values that sum to $value where each
        return value is a portion of $value allocated by the respective
        weights in @weights. The number of return values is equal to the
        number of elements in @weights

        $value must be an integer.

AUTHOR
    Marc Mims <marc@questright.com>

LICENSE
    Copyright (c) 2009 Marc Mims

    This is free software. You may use it, distributed it, and modify it
    under the same terms as Perl itself.

Blog | Support | Training | Contact | API | Status | Twitter | Help | Security
© 2010 GitHub Inc. All rights reserved. | Terms of Service | Privacy Policy
Powered by the Dedicated Servers and
Cloud Computing of Rackspace Hosting®
Dedicated Server