1ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#!/usr/local/bin/perl
2ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#  ********************************************************************
3ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#  * COPYRIGHT:
4ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#  * Copyright (c) 2002, International Business Machines Corporation and
5ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#  * others. All Rights Reserved.
6ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#  ********************************************************************
7ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
8ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querumy $PLUS_MINUS = "±";
9ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
10ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|#---------------------------------------------------------------------
11ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|# Format a confidence interval, as given by a Dataset.  Output is as
12ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|# as follows:
13ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|#   241.23 - 241.98 => 241.5 +/- 0.3
14ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|#   241.2 - 243.8 => 242 +/- 1
15ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|#   211.0 - 241.0 => 226 +/- 15 or? 230 +/- 20
16ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|#   220.3 - 234.3 => 227 +/- 7
17ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|#   220.3 - 300.3 => 260 +/- 40
18ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|#   220.3 - 1000 => 610 +/- 390 or? 600 +/- 400
19ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|#   0.022 - 0.024 => 0.023 +/- 0.001
20ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|#   0.022 - 0.032 => 0.027 +/- 0.005
21ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|#   0.022 - 1.000 => 0.5 +/- 0.5
22ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|# In other words, take one significant digit of the error value and
23ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|# display the mean to the same precision.
24ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|sub formatDataset {
25ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|    my $ds = shift;
26ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|    my $lower = $ds->getMean() - $ds->getError();
27ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|    my $upper = $ds->getMean() + $ds->getError();
28ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|    my $scale = 0;
29ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|    # Find how many initial digits are the same
30ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|    while ($lower < 1 ||
31ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|           int($lower) == int($upper)) {
32ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|        $lower *= 10;
33ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|        $upper *= 10;
34ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|        $scale++;
35ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|    }
36ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|    while ($lower >= 10 &&
37ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|           int($lower) == int($upper)) {
38ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|        $lower /= 10;
39ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|        $upper /= 10;
40ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|        $scale--;
41ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|    }
42ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#|}
43ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
44ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#---------------------------------------------------------------------
45ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru# Format a number, optionally with a +/- delta, to n significant
46ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru# digits.
47ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#
48ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru# @param significant digit, a value >= 1
49ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru# @param multiplier
50ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru# @param time in seconds to be formatted
51ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru# @optional delta in seconds
52ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#
53ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru# @return string of the form "23" or "23 +/- 10".
54ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#
55ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querusub formatNumber {
56ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    my $sigdig = shift;
57ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    my $mult = shift;
58ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    my $a = shift;
59ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    my $delta = shift; # may be undef
60ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
61ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    my $result = formatSigDig($sigdig, $a*$mult);
62ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (defined($delta)) {
63ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        my $d = formatSigDig($sigdig, $delta*$mult);
64ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        # restrict PRECISION of delta to that of main number
65ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if ($result =~ /\.(\d+)/) {
66ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            # TODO make this work for values with all significant
67ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            # digits to the left of the decimal, e.g., 1234000.
68ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
69ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            # TODO the other thing wrong with this is that it
70ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            # isn't rounding the $delta properly.  Have to put
71ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            # this logic into formatSigDig().
72ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            my $x = length($1);
73ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            $d =~ s/\.(\d{$x})\d+/.$1/;
74ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
75ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        $result .= " $PLUS_MINUS " . $d;
76ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
77ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    $result;
78ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
79ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
80ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#---------------------------------------------------------------------
81ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru# Format a time, optionally with a +/- delta, to n significant
82ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru# digits.
83ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#
84ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru# @param significant digit, a value >= 1
85ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru# @param time in seconds to be formatted
86ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru# @optional delta in seconds
87ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#
88ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru# @return string of the form "23 ms" or "23 +/- 10 ms".
89ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#
90ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querusub formatSeconds {
91ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    my $sigdig = shift;
92ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    my $a = shift;
93ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    my $delta = shift; # may be undef
94ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
95ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    my @MULT = (1   , 1e3,  1e6,  1e9);
96ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    my @SUFF = ('s' , 'ms', 'us', 'ns');
97ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
98ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    # Determine our scale
99ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    my $i = 0;
100ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    #always do seconds if the following line is commented out
101ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    ++$i while ($a*$MULT[$i] < 1 && $i < @MULT);
102ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
103ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    formatNumber($sigdig, $MULT[$i], $a, $delta) . ' ' . $SUFF[$i];
104ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
105ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
106ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#---------------------------------------------------------------------
107ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru# Format a percentage, optionally with a +/- delta, to n significant
108ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru# digits.
109ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#
110ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru# @param significant digit, a value >= 1
111ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru# @param value to be formatted, as a fraction, e.g. 0.5 for 50%
112ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru# @optional delta, as a fraction
113ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#
114ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru# @return string of the form "23 %" or "23 +/- 10 %".
115ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#
116ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querusub formatPercent {
117ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    my $sigdig = shift;
118ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    my $a = shift;
119ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    my $delta = shift; # may be undef
120ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
121ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    formatNumber($sigdig, 100, $a, $delta) . '%';
122ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
123ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
124ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#---------------------------------------------------------------------
125ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru# Format a number to n significant digits without using exponential
126ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru# notation.
127ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#
128ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru# @param significant digit, a value >= 1
129ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru# @param number to be formatted
130ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#
131ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru# @return string of the form "1234" "12.34" or "0.001234".  If
132ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#         number was negative, prefixed by '-'.
133ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#
134ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querusub formatSigDig {
135ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    my $n = shift() - 1;
136ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    my $a = shift;
137ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
138ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    local $_ = sprintf("%.${n}e", $a);
139ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    my $sign = (s/^-//) ? '-' : '';
140ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
141ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    my $a_e;
142ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    my $result;
143ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (/^(\d)\.(\d+)e([-+]\d+)$/) {
144ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        my ($d, $dn, $e) = ($1, $2, $3);
145ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        $a_e = $e;
146ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        $d .= $dn;
147ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        $e++;
148ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        $d .= '0' while ($e > length($d));
149ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        while ($e < 1) {
150ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            $e++;
151ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            $d = '0' . $d;
152ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
153ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if ($e == length($d)) {
154ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            $result = $sign . $d;
155ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        } else {
156ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            $result = $sign . substr($d, 0, $e) . '.' . substr($d, $e);
157ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
158ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else {
159ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        die "Can't parse $_";
160ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
161ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    $result;
162ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
163ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
164ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru1;
165ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
166ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#eof
167