12e5b6d6dSopenharmony_ci#!/usr/local/bin/perl 22e5b6d6dSopenharmony_ci# ******************************************************************** 32e5b6d6dSopenharmony_ci# * COPYRIGHT: 42e5b6d6dSopenharmony_ci# * © 2016 and later: Unicode, Inc. and others. 52e5b6d6dSopenharmony_ci# * License & terms of use: http://www.unicode.org/copyright.html 62e5b6d6dSopenharmony_ci# * Copyright (c) 2006, International Business Machines Corporation and 72e5b6d6dSopenharmony_ci# * others. All Rights Reserved. 82e5b6d6dSopenharmony_ci# ******************************************************************** 92e5b6d6dSopenharmony_ci 102e5b6d6dSopenharmony_cimy $PLUS_MINUS = "±"; 112e5b6d6dSopenharmony_ci 122e5b6d6dSopenharmony_ci#|#--------------------------------------------------------------------- 132e5b6d6dSopenharmony_ci#|# Format a confidence interval, as given by a Dataset. Output is as 142e5b6d6dSopenharmony_ci#|# as follows: 152e5b6d6dSopenharmony_ci#|# 241.23 - 241.98 => 241.5 +/- 0.3 162e5b6d6dSopenharmony_ci#|# 241.2 - 243.8 => 242 +/- 1 172e5b6d6dSopenharmony_ci#|# 211.0 - 241.0 => 226 +/- 15 or? 230 +/- 20 182e5b6d6dSopenharmony_ci#|# 220.3 - 234.3 => 227 +/- 7 192e5b6d6dSopenharmony_ci#|# 220.3 - 300.3 => 260 +/- 40 202e5b6d6dSopenharmony_ci#|# 220.3 - 1000 => 610 +/- 390 or? 600 +/- 400 212e5b6d6dSopenharmony_ci#|# 0.022 - 0.024 => 0.023 +/- 0.001 222e5b6d6dSopenharmony_ci#|# 0.022 - 0.032 => 0.027 +/- 0.005 232e5b6d6dSopenharmony_ci#|# 0.022 - 1.000 => 0.5 +/- 0.5 242e5b6d6dSopenharmony_ci#|# In other words, take one significant digit of the error value and 252e5b6d6dSopenharmony_ci#|# display the mean to the same precision. 262e5b6d6dSopenharmony_ci#|sub formatDataset { 272e5b6d6dSopenharmony_ci#| my $ds = shift; 282e5b6d6dSopenharmony_ci#| my $lower = $ds->getMean() - $ds->getError(); 292e5b6d6dSopenharmony_ci#| my $upper = $ds->getMean() + $ds->getError(); 302e5b6d6dSopenharmony_ci#| my $scale = 0; 312e5b6d6dSopenharmony_ci#| # Find how many initial digits are the same 322e5b6d6dSopenharmony_ci#| while ($lower < 1 || 332e5b6d6dSopenharmony_ci#| int($lower) == int($upper)) { 342e5b6d6dSopenharmony_ci#| $lower *= 10; 352e5b6d6dSopenharmony_ci#| $upper *= 10; 362e5b6d6dSopenharmony_ci#| $scale++; 372e5b6d6dSopenharmony_ci#| } 382e5b6d6dSopenharmony_ci#| while ($lower >= 10 && 392e5b6d6dSopenharmony_ci#| int($lower) == int($upper)) { 402e5b6d6dSopenharmony_ci#| $lower /= 10; 412e5b6d6dSopenharmony_ci#| $upper /= 10; 422e5b6d6dSopenharmony_ci#| $scale--; 432e5b6d6dSopenharmony_ci#| } 442e5b6d6dSopenharmony_ci#|} 452e5b6d6dSopenharmony_ci 462e5b6d6dSopenharmony_ci#--------------------------------------------------------------------- 472e5b6d6dSopenharmony_ci# Format a number, optionally with a +/- delta, to n significant 482e5b6d6dSopenharmony_ci# digits. 492e5b6d6dSopenharmony_ci# 502e5b6d6dSopenharmony_ci# @param significant digit, a value >= 1 512e5b6d6dSopenharmony_ci# @param multiplier 522e5b6d6dSopenharmony_ci# @param time in seconds to be formatted 532e5b6d6dSopenharmony_ci# @optional delta in seconds 542e5b6d6dSopenharmony_ci# 552e5b6d6dSopenharmony_ci# @return string of the form "23" or "23 +/- 10". 562e5b6d6dSopenharmony_ci# 572e5b6d6dSopenharmony_cisub formatNumber { 582e5b6d6dSopenharmony_ci my $sigdig = shift; 592e5b6d6dSopenharmony_ci my $mult = shift; 602e5b6d6dSopenharmony_ci my $a = shift; 612e5b6d6dSopenharmony_ci my $delta = shift; # may be undef 622e5b6d6dSopenharmony_ci 632e5b6d6dSopenharmony_ci my $result = formatSigDig($sigdig, $a*$mult); 642e5b6d6dSopenharmony_ci if (defined($delta)) { 652e5b6d6dSopenharmony_ci my $d = formatSigDig($sigdig, $delta*$mult); 662e5b6d6dSopenharmony_ci # restrict PRECISION of delta to that of main number 672e5b6d6dSopenharmony_ci if ($result =~ /\.(\d+)/) { 682e5b6d6dSopenharmony_ci # TODO make this work for values with all significant 692e5b6d6dSopenharmony_ci # digits to the left of the decimal, e.g., 1234000. 702e5b6d6dSopenharmony_ci 712e5b6d6dSopenharmony_ci # TODO the other thing wrong with this is that it 722e5b6d6dSopenharmony_ci # isn't rounding the $delta properly. Have to put 732e5b6d6dSopenharmony_ci # this logic into formatSigDig(). 742e5b6d6dSopenharmony_ci my $x = length($1); 752e5b6d6dSopenharmony_ci $d =~ s/\.(\d{$x})\d+/.$1/; 762e5b6d6dSopenharmony_ci } 772e5b6d6dSopenharmony_ci $result .= " $PLUS_MINUS " . $d; 782e5b6d6dSopenharmony_ci } 792e5b6d6dSopenharmony_ci $result; 802e5b6d6dSopenharmony_ci} 812e5b6d6dSopenharmony_ci 822e5b6d6dSopenharmony_ci#--------------------------------------------------------------------- 832e5b6d6dSopenharmony_ci# Format a time, optionally with a +/- delta, to n significant 842e5b6d6dSopenharmony_ci# digits. 852e5b6d6dSopenharmony_ci# 862e5b6d6dSopenharmony_ci# @param significant digit, a value >= 1 872e5b6d6dSopenharmony_ci# @param time in seconds to be formatted 882e5b6d6dSopenharmony_ci# @optional delta in seconds 892e5b6d6dSopenharmony_ci# 902e5b6d6dSopenharmony_ci# @return string of the form "23 ms" or "23 +/- 10 ms". 912e5b6d6dSopenharmony_ci# 922e5b6d6dSopenharmony_cisub formatSeconds { 932e5b6d6dSopenharmony_ci my $sigdig = shift; 942e5b6d6dSopenharmony_ci my $a = shift; 952e5b6d6dSopenharmony_ci my $delta = shift; # may be undef 962e5b6d6dSopenharmony_ci 972e5b6d6dSopenharmony_ci my @MULT = (1 , 1e3, 1e6, 1e9); 982e5b6d6dSopenharmony_ci my @SUFF = ('s' , 'ms', 'us', 'ns'); 992e5b6d6dSopenharmony_ci 1002e5b6d6dSopenharmony_ci # Determine our scale 1012e5b6d6dSopenharmony_ci my $i = 0; 1022e5b6d6dSopenharmony_ci #always do seconds if the following line is commented out 1032e5b6d6dSopenharmony_ci ++$i while ($a*$MULT[$i] < 1 && $i < @MULT); 1042e5b6d6dSopenharmony_ci 1052e5b6d6dSopenharmony_ci formatNumber($sigdig, $MULT[$i], $a, $delta) . ' ' . $SUFF[$i]; 1062e5b6d6dSopenharmony_ci} 1072e5b6d6dSopenharmony_ci 1082e5b6d6dSopenharmony_ci#--------------------------------------------------------------------- 1092e5b6d6dSopenharmony_ci# Format a percentage, optionally with a +/- delta, to n significant 1102e5b6d6dSopenharmony_ci# digits. 1112e5b6d6dSopenharmony_ci# 1122e5b6d6dSopenharmony_ci# @param significant digit, a value >= 1 1132e5b6d6dSopenharmony_ci# @param value to be formatted, as a fraction, e.g. 0.5 for 50% 1142e5b6d6dSopenharmony_ci# @optional delta, as a fraction 1152e5b6d6dSopenharmony_ci# 1162e5b6d6dSopenharmony_ci# @return string of the form "23 %" or "23 +/- 10 %". 1172e5b6d6dSopenharmony_ci# 1182e5b6d6dSopenharmony_cisub formatPercent { 1192e5b6d6dSopenharmony_ci my $sigdig = shift; 1202e5b6d6dSopenharmony_ci my $a = shift; 1212e5b6d6dSopenharmony_ci my $delta = shift; # may be undef 1222e5b6d6dSopenharmony_ci 1232e5b6d6dSopenharmony_ci formatNumber($sigdig, 100, $a, $delta) . '%'; 1242e5b6d6dSopenharmony_ci} 1252e5b6d6dSopenharmony_ci 1262e5b6d6dSopenharmony_ci#--------------------------------------------------------------------- 1272e5b6d6dSopenharmony_ci# Format a number to n significant digits without using exponential 1282e5b6d6dSopenharmony_ci# notation. 1292e5b6d6dSopenharmony_ci# 1302e5b6d6dSopenharmony_ci# @param significant digit, a value >= 1 1312e5b6d6dSopenharmony_ci# @param number to be formatted 1322e5b6d6dSopenharmony_ci# 1332e5b6d6dSopenharmony_ci# @return string of the form "1234" "12.34" or "0.001234". If 1342e5b6d6dSopenharmony_ci# number was negative, prefixed by '-'. 1352e5b6d6dSopenharmony_ci# 1362e5b6d6dSopenharmony_cisub formatSigDig { 1372e5b6d6dSopenharmony_ci my $n = shift() - 1; 1382e5b6d6dSopenharmony_ci my $a = shift; 1392e5b6d6dSopenharmony_ci 1402e5b6d6dSopenharmony_ci local $_ = sprintf("%.${n}e", $a); 1412e5b6d6dSopenharmony_ci my $sign = (s/^-//) ? '-' : ''; 1422e5b6d6dSopenharmony_ci 1432e5b6d6dSopenharmony_ci my $a_e; 1442e5b6d6dSopenharmony_ci my $result; 1452e5b6d6dSopenharmony_ci if (/^(\d)\.(\d+)e([-+]\d+)$/) { 1462e5b6d6dSopenharmony_ci my ($d, $dn, $e) = ($1, $2, $3); 1472e5b6d6dSopenharmony_ci $a_e = $e; 1482e5b6d6dSopenharmony_ci $d .= $dn; 1492e5b6d6dSopenharmony_ci $e++; 1502e5b6d6dSopenharmony_ci $d .= '0' while ($e > length($d)); 1512e5b6d6dSopenharmony_ci while ($e < 1) { 1522e5b6d6dSopenharmony_ci $e++; 1532e5b6d6dSopenharmony_ci $d = '0' . $d; 1542e5b6d6dSopenharmony_ci } 1552e5b6d6dSopenharmony_ci if ($e == length($d)) { 1562e5b6d6dSopenharmony_ci $result = $sign . $d; 1572e5b6d6dSopenharmony_ci } else { 1582e5b6d6dSopenharmony_ci $result = $sign . substr($d, 0, $e) . '.' . substr($d, $e); 1592e5b6d6dSopenharmony_ci } 1602e5b6d6dSopenharmony_ci } else { 1612e5b6d6dSopenharmony_ci die "Can't parse $_"; 1622e5b6d6dSopenharmony_ci } 1632e5b6d6dSopenharmony_ci $result; 1642e5b6d6dSopenharmony_ci} 1652e5b6d6dSopenharmony_ci 1662e5b6d6dSopenharmony_ci1; 1672e5b6d6dSopenharmony_ci 1682e5b6d6dSopenharmony_ci#eof 169