Perl Quiz-of-the-Week #7

Mark Jason Dominus <[email protected]> Wed, 27 Nov 2002 18:31:19 -0500
Newsgroups gmane.comp.lang.perl.qotw.quiz-of-the-week
Organization Plover Systems
Message-ID <[email protected]>
IMPORTANT: Please do not post solutions, hints, or other spoilers
        until at least 60 hours after the date of this message.
        Thanks.

IMPORTANTE: Por favor, no enviéis soluciones, pistas, o cualquier otra
        cosa que pueda echar a perder la resolución del problema hasta
        que hayan pasado por lo menos 60 horas desde el envío de este
        mensaje. Gracias.

IMPORTANT: S'il vous plaît, attendez au minimum 60 heures après la
        date de ce message avant de poster solutions, indices ou autres
        révélations. Merci.

WICHTIG: Bitte schicken Sie keine Lösungen, Tipps oder Hinweise für
        diese Aufgabe vor Ablauf von 60 Stunden nach dem Datum dieser
        Mail. Danke.

BELANGRIJK: Stuur aub geen oplossingen, hints of andere tips in de
        eerste 60 uur na het verzendingstijdstip van dit
        bericht. Waarvoor dank.

Qing3 Zhu4Yi4: Qing3 Ning2 Deng3Dao4 Jie1Dao4 Ben3 Xin4Xi2 Zhi1Hou4 60
        Xiao3Shi2, Zai4 Fa1Biao3 Jie3Da2, Ti2Shi4, Huo4 Qi2Ta1 Hui4
        Xie4Lou4 Da2An4 De5 Jian4Yi4.  Xie4Xie4.

----------------------------------------------------------------

A gentleman on the perl-qotw-discuss list reports:

> In two different companies that I've worked at, the policy has been
> that percentages in reports must always add up to 100% (at the cost
> of munging the actual data).  It seems that otherwise end users
> report it as a bug.

This means, for example, that if you survey 300 people and find that
100 prefer the color red, 100 prefer blue, and 100 prefer black, you
are not allowed to report

        33.3 % prefer red
        33.3 % prefer blue
        33.3 % prefer black

Because then the percentages appear to add up to only 99.9%.  Instead,
you'll fib, by rounding one of the percentages up to 33.4% instead of
down to 33.3 %:

        33.3 % prefer red
        33.4 % prefer blue
        33.3 % prefer black

This, of course, is ridiculous, since it suggests that there were
somehow more 'blue' responses than 'red' or 'black' responses, when
there were in fact equal numbers of each.  But in the world of
business the appearance of correctness is sometimes more important
than actual correctness.

Similarly, if you survey 70 people and find that 30 prefer red, 30
prefer blue, and 10 prefer black, you may not say that

        42.9 % prefer red
        42.9 % prefer blue
        14.3 % prefer black

because the percentages appear to add up to 100.1%.  You must adjust
one of the percentages down by 0.1%.

You will write a function, 'fudge_numbers', which takes the real data
as input and returns the appropriate percentages.

All arguments to fudge_numbers(), except the first, will be the actual
data, which will all be non-negative numbers.

The return value of fudge_numbers() will be a list of numbers that
express the data items as relative percentages of their total.  There
must be exactly one return value for each data argument, and the
return values must total exactly 100.  (Or as near as possible within
the computer's limits of precision.)  The percentages you return may
differ from the true percentages be no more than 1 in the last decimal
place.

The first argument to fudge_numbers() will be special: It will be an
integer, 0 or greater, indicating how many places after the decimal
point will be retained when rounding the percentages.  An argument of
1 will mean that the percentages you return would be rounded to the
nearest tenth of a percent, as in the examples above.  An argument of
0 will mean that the percentages should be rounded to the nearest
percent; an argument of 2 will mean that the percentages should be
rounded to the nearest hundredth of a percent; other numbers
similarly.  

For example, 

        fudge_numbers(1, 100, 100, 100) 

should return

        (33.4, 33.3, 33.3)
or
        (33.3, 33.4, 33.3)
or
        (33.3, 33.3, 33.4)

(All are equally acceptable; (33.5, 33.3, 33.2) is not.)

Similarly:

        Arguments                       Return values

        1, 100, 100, 100                33.3, 33.4, 33.3
        0, 100, 100, 100                33, 34, 33
        2, 100, 100, 100                33.33, 33.34, 33.33

        2, 7, 7, 7                      33.33, 33.34, 33.33
                
        1, 30, 30, 10                   42.9, 42.9, 14.2
                                     or 42.9, 42.8, 14.3
                                     or 42.8, 42.8, 14.3

        1 z                             100
                (here 'z' is any number)