How do I change a couple value/error from the value+-error format to the value(error)format?

StackOverflow https://stackoverflow.com/questions/12861569

  •  07-07-2021
  •  | 
  •  

Pergunta

I have a few data text files whose lines are values with their error, like these:

...
6  90.3785794742981 0.0952997386139722
40 1028.46336161948 4.41798447319325
...

the third column is the error relativley to the second column. I would like to write a script that prints them in a more human-readable format, that is to print the value with the right number of significant digits and to print the error on the last two digist between parenthesis, like this:

...
6  90.379(95)
40 1028.5(4.4)
...

using regular expressions to extract the numbers wouldn't work right because of difficulties of handling the dot and because it would truncate numbers rather than approximate them, so i thought that i'd rather retrieve their magnitude with printf and handle them with bc.

The code I wrote for this is as follows

#! /bin/bash
while read a v verr
do
    ov=`printf %e $v`
    ov=${ov/*e/}
    overr=`printf "%e" $verr`
    overr=${overr/*e/}
dov=$((1-$overr))
v=`echo "scale=0;$v*10^($dov)" | bc -l`
v=`printf %.0f $v`
printf "$a %f(%.0f)\n" `echo "lenght=length($v);$v*10^($((-$dov)))" | bc -l` `echo "$verr*10^($dov)" | bc -l`
 done < myfile.txt

what i get is

6 90.379000(95)
40 1028.500000(44)

My code almost works, except for the appearence of those trailing zeroes.

How do I get rid of them? Just cutting them would not be good because their number is not fixed and cutting them all would give rise to errors wheter the last digit actually is a zero.

Foi útil?

Solução

The following code works.

#! /bin/bash
while read a v verr
do
ov=`printf %e $v`
    ov=${ov/*e/}
    overr=`printf %e $verr`
overr=${overr/*e/}
dov=$((1-$overr))
v=`echo "scale=0;$v*10^($dov)" | bc -l`
v=`printf %.0f $v`

if [ $dov -gt 0 ]; then
    # remember bc doesn't understand numbers in scientific notation,
    # therefore we need to convert such numbers in regular notation.
    u=`echo ${u} | sed 's/[eE]/\\*10\\^/' | sed 's/+//'`
    verr=`echo ${verr} | sed 's/[eE]/\\*10\\^/' | sed 's/+//'`

    u=`echo "$v*10^($((-$dov)))" | bc -l`
    if [ $overr -eq 0 ]; then
    uerr=`echo "$verr*10^($dov - 1)" | bc -l`
    printf "$a\t%.${dov}f(%.1f)\n" $u $uerr>>$s
    else
    uerr=`echo "$verr*10^($dov)" | bc -l`
    printf "$a\t%.${dov}f(%.0f)\n" $u $uerr>>$s
    fi
else
    echo $a "${v}(${verr})E$ov">>$s
fi
done < $f

it prints the values formatted as I wanted. The first case tests whether it needs to express the result in exponential notation in order to get significant digits right, and the second if case tests wheter it should put a dot in the error.

I have not tested the third line of code from the bottom because I do not need it now, so be cautious because it might not work.

EDIT: I inserted two sed calls to handle scientific notation numbers.

Outras dicas

If using a sed command is ok for you, you can add a sed statement after your printf to remove the trailing zeros:

printf "$a %f(%.0f)\n" `echo "lenght=length($v);$v*10^($((-$dov)))" | bc -l` `echo "$verr*10^($dov)" | bc -l` | sed 's/00*(/(/'
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top