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.
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It only takes a minute to sign up.
Sign up to join this communityprintf
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
$
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.
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
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.
You may try the following:
echo "3.0000000000e+02" | awk '{printf("%d",$0);}'
or if you expect to have decimals
echo ""3.676361000e+02" | awk '{printf("%0.2f",$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
42.53e-12
can not be presented as0.04253
. Also, this "to do this for a list" requires detailed description/sample