Unix Shell - rounding up (or down) issue

This is Interesting: Free IT Magazines  
Home > Archive > Unix Shell > December 2007 > rounding up (or down) issue





You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

Author rounding up (or down) issue
Farid Hamjavar

2007-12-19, 1:23 pm


Greetings,

I have data lines in a file like these whose
components add up to 100:

1.73 0.45 98.72
1.88 23.11 75.01
16.88 0.88 82.24



Yet, when attempting to round down (or up)
resulting data will not be 100 in total:

e.g. 2nd row , rounded up:
2 24 75 = 101

e.g. 2nd row , rounded down:
1 23 75 = 99


I need to round them up (or down) for reporting
purpose in which the line show up like:

2% 24% 75% = 101%



How does one get round this?
i.e. Any way to get 100 after rounding up (or down)?


Thanks,
Farid


Janis Papanagnou

2007-12-19, 1:23 pm

Farid Hamjavar wrote:
> Greetings,
>
> I have data lines in a file like these whose
> components add up to 100:
>
> 1.73 0.45 98.72
> 1.88 23.11 75.01
> 16.88 0.88 82.24
>
>
>
> Yet, when attempting to round down (or up)
> resulting data will not be 100 in total:
>
> e.g. 2nd row , rounded up:
> 2 24 75 = 101
>
> e.g. 2nd row , rounded down:
> 1 23 75 = 99
>
>
> I need to round them up (or down) for reporting
> purpose in which the line show up like:
>
> 2% 24% 75% = 101%
>
>
>
> How does one get round this?


The (quite) most accurate way is to round arithmetically

round(x) = floor(x+0.5)

where floor() is trucation to the integral part. There
have been improvements suggested that are slightly better
than that; they consider whether specific digits are even
or odd to decide whether to round up or down in the case
that a value has exactly a least significant digit of 5,
otherwise it's rounded arithmetically. (I think that has
been mentioned in a paper called "What computer scientists
should know about floating point numbers." or so.) Anyway,
you'll always find numbers that won't fit.

> i.e. Any way to get 100 after rounding up (or down)?


No, that's in general not possible. If, as you do, reduce
precision and then add the numbers you'll not get what you
would like to have.

Janis

>
>
> Thanks,
> Farid
>
>

Bill Marcum

2007-12-19, 7:27 pm

["Followup-To:" header set to comp.unix.shell.]
On 2007-12-19, Farid Hamjavar <hamjavar@unm.edu> wrote:
>
>
>
> Greetings,
>
> I have data lines in a file like these whose
> components add up to 100:
>
> 1.73 0.45 98.72
> 1.88 23.11 75.01
> 16.88 0.88 82.24
>
>
>
> Yet, when attempting to round down (or up)
> resulting data will not be 100 in total:
>
> e.g. 2nd row , rounded up:
> 2 24 75 = 101
>
> e.g. 2nd row , rounded down:
> 1 23 75 = 99
>
>
> I need to round them up (or down) for reporting
> purpose in which the line show up like:
>
> 2% 24% 75% = 101%
>
>
>
> How does one get round this?
> i.e. Any way to get 100 after rounding up (or down)?
>

Round the sums after you add them, not before.
Rikishi 42

2007-12-19, 7:27 pm

On 2007-12-19, Janis Papanagnou <Janis_Papanagnou@hotmail.com> wrote:
> The (quite) most accurate way is to round arithmetically
>
> round(x) = floor(x+0.5)
>
> where floor() is trucation to the integral part. There
> have been improvements suggested that are slightly better
> than that; they consider whether specific digits are even
> or odd to decide whether to round up or down in the case
> that a value has exactly a least significant digit of 5,
> otherwise it's rounded arithmetically. (I think that has
> been mentioned in a paper called "What computer scientists
> should know about floating point numbers." or so.) Anyway,
> you'll always find numbers that won't fit.
>
>
> No, that's in general not possible. If, as you do, reduce
> precision and then add the numbers you'll not get what you
> would like to have.



A question to the OP: the 3 example rows have a rather larger third value.
Is that just random, or would that value be something like the remainder,
the eftover value? Is it allways much larger than the first 2 ?

If so, you could round the first 2, according to the usual (above) rule. You
could sthen ubstract the first 2 from 100, to obtain number 3.
100% -2% -24% = 74%

It's still wrong to do this, because it will be poorly rounded. But you'll
have a coherent display and it'll impact less for a large number, than for a
File /home/werner/.followup saved.


I'd just display 2 digits after the decimal point in the percentage.
But won't get you 100.00, mind you.

--
There is an art, it says, or rather, a knack to flying.
The knack lies in learning how to throw yourself at the ground and miss.
Douglas Adams
Ed Morton

2007-12-20, 1:40 am



On 12/19/2007 10:32 AM, Farid Hamjavar wrote:
> Greetings,
>
> I have data lines in a file like these whose
> components add up to 100:
>
> 1.73 0.45 98.72
> 1.88 23.11 75.01
> 16.88 0.88 82.24
>
>
>
> Yet, when attempting to round down (or up)
> resulting data will not be 100 in total:
>
> e.g. 2nd row , rounded up:
> 2 24 75 = 101
>
> e.g. 2nd row , rounded down:
> 1 23 75 = 99
>
>
> I need to round them up (or down) for reporting
> purpose in which the line show up like:
>
> 2% 24% 75% = 101%
>
>
>
> How does one get round this?
> i.e. Any way to get 100 after rounding up (or down)?
>


Getting 100 isn't the problem:

$ cat file
1.73 0.45 98.72
1.88 23.11 75.01
16.88 0.88 82.24

$ awk '{printf "%d\n", $1+$2+$3}' file
100
100
100

It's getting intermediate values that add up to 100 that's the problem:

$ awk '{printf "%d+%d+%d=%d\n",$1,$2,$3, $1+$2+$3}' file
1+0+98=100
1+23+75=100
16+0+82=100

Would it be acceptable to determine the total, round all but the largest value
however you like, and then subtract their sub-total from the real total to give
a replacement for the "rounded largest value"? e.g. something like this:

$ cat approx.awk
{
tot=maxVal=subTot=0
for (i=1;i<=NF;i++) {
if ($i > maxVal) {
maxVal = $i
maxFld = i
}
tot += $i
$i = int($i)
}

for (i=1;i<=NF;i++) {
if (i != maxFld) {
subTot += $i
}
}

$maxFld = tot - subTot

sep=""
for (i=1;i<=NF;i++) {
printf "%s%d",sep,$i
sep="+"
}
printf "=%d\n",tot
}

$ awk -f approx.awk file
1+0+99=100
1+23+76=100
16+0+84=100

Regards,

Ed.




Ed Morton

2007-12-20, 1:40 am



On 12/19/2007 11:40 PM, Ed Morton wrote:
>
> On 12/19/2007 10:32 AM, Farid Hamjavar wrote:
>
>
>
> Getting 100 isn't the problem:
>
> $ cat file
> 1.73 0.45 98.72
> 1.88 23.11 75.01
> 16.88 0.88 82.24
>
> $ awk '{printf "%d\n", $1+$2+$3}' file
> 100
> 100
> 100
>
> It's getting intermediate values that add up to 100 that's the problem:
>
> $ awk '{printf "%d+%d+%d=%d\n",$1,$2,$3, $1+$2+$3}' file
> 1+0+98=100
> 1+23+75=100
> 16+0+82=100
>
> Would it be acceptable to determine the total, round all but the largest value
> however you like, and then subtract their sub-total from the real total to give
> a replacement for the "rounded largest value"? e.g. something like this:


Fixed for better accuracy after seeing "round()" in Janis's earlier post:

$ cat approx.awk
{
tot=maxVal=subTot=0
for (i=1;i<=NF;i++) {
if ($i > maxVal) {
maxVal = $i
maxFld = i
}
tot += $i
$i = int($i+0.5)
}

for (i=1;i<=NF;i++) {
if (i != maxFld) {
subTot += $i
}
}

$maxFld = tot - subTot

sep=""
for (i=1;i<=NF;i++) {
printf "%s%d",sep,$i
sep="+"
}
printf "=%d\n",tot
}

$ awk -f approx.awk file
2+0+98=100
2+23+75=100
17+1+82=100

Regards,

Ed.

Sponsored Links






Free braindumps | Software forum | Database administration forum

Copyright 2003 - 2008 webservertalk.com