2

How to convert value from scientific notation to decimal in shell? (preferred C shell)

Also I'd want to convert it from e-12 to e-9 and then shell

42.53e-12 to 0.04253. I have to do this for a list.

  • 42.53e-12 can not be presented as 0.04253. Also, this "to do this for a list" requires detailed description/sample – RomanPerekhrest Feb 11 '18 at 21:32
5

printf will do this for you, from shell.

 $ FOO=42.53e-12
 $ BAR=$(printf "%.14f" $FOO)
 $ echo $BAR
 0.00000000004253
 $

In ancient+arcane C-shell, this would be.

$ set FOO=42.53e-12
$ set BAR=`printf "%.14f" $FOO`
$ echo $BAR
0.00000000004253
$
1

shell

Many shells (specially ancient+arcane csh) don't understand floating point arithmetic.

In most shells there is a builtin printf which understands "scientific format".

$ printf '%5.0f\n' '1e3'
 1000

But all printf could not do math:

$ printf '%5.0f\n' '1e3+1e3'
printf: ‘1e3+1e3’: value not completely converted

There is a workaround in two steps for csh. - First
Convert the number to a decimal of less than 18 digits (for a 53 bit significant of a 64 bit float)[a]:

    % printf "%.18f\n" "42.53e-12"
    0.000000000042530000
  • Second
    Multiply by 1e3 (as you requested) and print again:

    % printf '%.15f\n' "`printf "%.18f" "42.53e-12"`e3"
    0.000000042530000
    

Of course, printf in csh is an external utility with its own float size (64 bit?) and may be different for a different OS.

Math tools.

To do math (other than the shell) it is natural to think of bc, but bc has its own limitations (doesn't understand the e as exponent, it has to be converted to 10^). Read this.

But awk could do it:

% echo 42.53e-12 | awk '{printf("%.15f\n", $1*1e3)}'
0.000000042530000

Don't expect more than 15 correct digits as awk use a 53 bit significant. To have more, you need the GNU version of awk with the arbitrary precision module compiled in.

% echo 42.53e-12 | awk -M -v PREC=134 '{printf("%.40g\n", $1*1e3)}'
4.253e-08

That is 134 binary bits for (up to) 40 decimal digits. As a decimal:

% echo 42.53e-12 | awk -M -v PREC=134 '{printf("%.40f\n", $1*1e3)}'
0.0000000425300000000000000000000000000000

list

In your question, you state:

I have to do this for a list.

But give no details of what kind of list it is. If the list is inside a file (not as a shell variable) you need nothing from csh (or any other shell) except to execute this:

% awk '{printf("%.15f\n", $1*1e3)}' <file

The same precision limitations as above still apply.


[a] Actually, to be technically exact, you should limit the number of digits with the %g printf format first, so the pedantically correct solution is a three level transformation.

In any reasonable shell (ksh,bash,zsh) this will work:

$ bash -c 'printf "%.15f\n" "$(printf "%.18f" "$( printf "%.18g" "42.53e-12")" )e3"'
0.000000042530000

But quoting a double ` ` is really awkward in csh, and csh use set to assign to vars. In short, this will work for csh:

$ csh -c 'set a=`printf "%.18g" "42.53e-12"`; set a=`printf "%.18f" "$a"`; printf "%.18f\n" "${a}e3"'
0.000000042530000000

But, I really, really! think that you should avoid csh.

0

Might not be the best solution but I managed to do it with a little hack. You can do something like this -

scientific='42.53e-12'
base=$(echo $scientific | cut -d 'e' -f1)
exp=$(($(echo $scientific | cut -d 'e' -f2)*1))
converted=$(bc -l <<< "$base*(10^$exp)")
>> .00000000004253000000

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.