bc
科学的記数法(別名指数表記法)で表現された数値は好きではありません。
$ echo "3.1e1*2" | bc -l
(standard_in) 1: parse error
しかし、この表記で表現されるいくつかのレコードを処理するためにそれを使用する必要があります。bc
指数表記を理解する方法はありますか?bc
そうでない場合、それらを理解できる形式に翻訳するにはどうすればよいですか?
bc
科学的記数法(別名指数表記法)で表現された数値は好きではありません。
$ echo "3.1e1*2" | bc -l
(standard_in) 1: parse error
しかし、この表記で表現されるいくつかのレコードを処理するためにそれを使用する必要があります。bc
指数表記を理解する方法はありますか?bc
そうでない場合、それらを理解できる形式に翻訳するにはどうすればよいですか?
残念ながら、bcは科学的記数法をサポートしていません。
ただし、 sedのPOSIXに従って拡張正規表現を使用して、bcが処理できる形式に変換できます。
sed -E 's/([+-]?[0-9.]+)[eE]\+?(-?)([0-9]+)/(\1*10^\2\3)/g' <<<"$value"
「e」(指数が正の場合は「e +」)を「* 10 ^」に置き換えることができます。これは、bcがすぐに理解します。これは、指数が負の場合、または数値に後で別の累乗を掛けた場合でも機能し、有効数字を追跡できます。
基本的な正規表現(BRE)に固執する必要がある場合は、これを使用する必要があります。
sed 's/\([+-]\{0,1\}[0-9]*\.\{0,1\}[0-9]\{1,\}\)[eE]+\{0,1\}\(-\{0,1\}\)\([0-9]\{1,\}\)/(\1*10^\2\3)/g' <<<"$value"
コメントから:
e +を一致させ、同時に-をe-から保持する方法がないため、単純なbashパターン一致は機能しませんでした(@ mklement0に感謝)。
正しく機能するperlソリューション(@ mklement0に感謝)
$ perl -pe 's/([-\d.]+)e(?:\+|(-))?(\d+)/($1*10^$2$3)/gi' <<<"$value"
sedの構文の側面を明確にしてくれた@jwpat7と@PaulTomblin 、そして答えを改善してくれた@isaacと@mklement0に感謝します。
編集:
答えは何年にもわたってかなり変わりました。上記の答えは、2018年5月17日現在の最新の反復です。ここで報告された以前の試みは、純粋なbash(@ormaajによる)とsed(@meによる)の解決策でしたが、少なくともいくつかのケースで失敗しました。コメントを理解するために、ここにそれらを保持します。コメントには、この回答よりもはるかに複雑な説明が含まれています。
value=${value/[eE]+*/*10^} ------> Can not work.
value=`echo ${value} | sed -e 's/[eE]+*/\\*10\\^/'` ------> Fail in some conditions
以下のそれぞれについてコメントを付けて、既存の回答を要約してみましょう。
bc
(a)OPのように、実際に任意精度の計算に使用する必要がある場合は、OP独自の巧妙なアプローチを使用します。これは、科学的記数法を理解できる同等の式にテキストbc
で再フォーマットします。
精度が失われる可能性が問題にならない場合は、
awk
または代替手段perl
としてbc
の使用を検討してください。jwpat7のawkに対する回答に示されているように、どちらも科学的記数法をネイティブに理解しています。printf '%.<precision>f'
に単純にテキスト変換するe
E
ことを検討してください( ormaajによって削除された投稿で提案された解決策)。bc
式に再フォーマットするこのソリューションの利点は、精度が維持されることです。テキスト表現は、理解できる同等のテキスト表現に変換され、それ自体が任意精度の計算が可能です。bc
bc
OP自身の回答を参照してください。この回答の更新された形式では、指数表記の複数の数値を含む式全体を同等の式に変換できるようになりましたbc
。
awk
またはperl
代わりに使用するbc
注:以下のアプローチは、およびの倍精度浮動小数点値の組み込みサポートの使用を前提としていawk
perl
ます。浮動小数点演算に固有のように、
「任意の固定ビット数を指定すると、実数を使用したほとんどの計算では、その数のビットを使用して正確に表すことができない量が生成されます。したがって、浮動小数点計算の結果は、多くの場合、丸める必要があります。この丸め誤差は、浮動小数点計算の特徴です。」(http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html)
そうは言っても、
GNU awkは、任意精度の演算をサポートして構築するオプションを提供します。https://www.gnu.org/software/gawk/manual/html_node/Gawk-and-MPFR.htmlを参照してください。ただし、ディストリビューションにはそのサポートが含まれる場合と含まれない場合があります。forおよび。からの出力を確認してサポートを確認してください。
サポートが利用可能な場合は、特定の呼び出しで( )を使用してサポートをアクティブ化する必要があります。gawk --version
GNU MPFR
GNU MP
-M
--bignum
Perlは、パッケージを介してオプションの任意精度の小数サポートを提供します-https://metacpan.org/pod/Math::BigFloatを参照してくださいMath::BigFloat
awk
awk
10進指数(科学)表記をネイティブに理解します。(実装は他の基数で数値リテラルをサポートするかどうかに関して異なるため、
通常は10進表現のみを使用する必要があります。)awk
awk 'BEGIN { print 3.1e1 * 2 }' # -> 62
デフォルトのprint
関数を使用する場合、OFMT
変数はprintf
フォーマット文字列を介して出力フォーマットを制御します。(POSIXで必須の)デフォルトは%.6g
、有効数字6桁を意味します。これには、特に整数部分の数字が含まれます。
科学的記数法の数値が(awkプログラムのリテラル部分ではなく)入力として提供される場合、それを+0
デフォルトの出力形式に強制的に追加する必要があることに注意してください。print
ロケールと使用する実装によっては、小数点( )をドイツ語ロケールなどのロケールに適した基数文字awk
に置き換える必要がある場合があります。BSD、、およびオプション付きのGNUに適用されます。.
,
awk
mawk
awk
--posix
awk '{ print $1+0 }' <<<'3.1e1' # -> 31; without `+0`, output would be the same as input
変数OFMT
を変更すると、デフォルトの出力形式が変更されます(小数部の数値の場合、(有効な)整数は常にそのまま出力されます)。または、明示的な出力形式で関数
を
使用します。printf
awk 'BEGIN { printf "%.4f", 3.1e1 * 2.1234 }' # -> 65.8254
Perl
perl
10進指数(科学的)表記をネイティブに理解しすぎています。
注:Perlは、awkとは異なり、デフォルトではすべてのPOSIXのようなプラットフォームで使用できるわけではありません。さらに、awkほど軽量ではありません。
ただし、16進整数と8進整数をネイティブに理解するなど、awkよりも多くの機能を提供します。
perl -le 'print 3.1e1 * 2' # -> 62
Perlのデフォルトの出力形式が何であるかはわかりませんが、そうであるよう%.15g
です。awkと同様に、使用printf
して目的の出力形式を選択できます。
perl -e 'printf "%.4f\n", 3.1e1 * 2.1234' # -> 65.8254
printf
科学的記数法を小数に変換するために使用する1.2e-2
科学的記数法(たとえば)を小数(たとえば)0.012
に変換したいだけの場合は、printf '%f'
それを行うことができます。浮動小数点演算を介して、あるテキスト表現を別のテキスト表現に変換することに注意してください。これは、およびアプローチと同じ丸め誤差の影響を受けます。awk
perl
printf '%.4f' '1.2e-2' # -> '0.0120'; `.4` specifies 4 decimal digits.
これにはawkを使用できます。例えば、
awk '{ print +$1, +$2, +$3 }' <<< '12345678e-6 0.0314159e2 54321e+13'
12.3457 3.14159 543210000000000000
次の2つのようなコマンドは、後で示すようにファイルedata
にデータが含まれている場合、それぞれの後に示される出力を生成しますが、 (awkのデフォルト形式%.6gを介して)出力を生成します。
$ awk '{for(i=1;i<=NF;++i)printf"%.13g ",+$i; printf"\n"}' < edata`
31 0.0312 314.15 0
123000 3.1415965 7 0.04343 0 0.1
1234567890000 -56.789 -30
$ awk '{for(i=1;i<=NF;++i)printf"%9.13g ",+$i; printf"\n"}' < edata
31 0.0312 314.15 0
123000 3.1415965 7 0.04343 0 0.1
1234567890000 -56.789 -30
$ cat edata
3.1e1 3.12e-2 3.1415e+2 xyz
123e3 0.031415965e2 7 .4343e-1 0e+0 1e-1
.123456789e13 -56789e-3 -30
また、を使用するソリューションに関しては、別の式ではなく、正規表現を介して、のsed
ような形式でプラス記号を削除する方がおそらく適切です。たとえば、GNU sedバージョン4.2.1およびbashバージョン4.2.24を搭載したLinuxマシンでは、コマンド
によって出力が生成されます。45e+3
e
[eE]+*
sed
sed 's/[eE]+*/*10^/g' <<< '7.11e-2 + 323e+34'
sed 's/[eE]+*/*10^/g' <<< '7.11e-2 + 323e+34' | bc -l
7.11*10^-2 + 323*10^34
3230000000000000000000000000000000000.07110000000000000000
awkを呼び出すbash関数を定義することもできます(適切な名前は等号 "=")です。
= ()
{
local in="$(echo "$@" | sed -e 's/\[/(/g' -e 's/\]/)/g')";
awk 'BEGIN {print '"$in"'}' < /dev/null
}
次に、シェルですべてのタイプの浮動小数点演算を使用できます。ここでは丸括弧の代わりに角括弧が使用されていることに注意してください。丸括弧は引用符でバッシュから保護する必要があるためです。
> = 1+sin[3.14159] + log[1.5] - atan2[1,2] - 1e5 + 3e-10
0.94182
または、スクリプトで結果を割り当てます
a=$(= 1+sin[4])
echo $a # 0.243198
幸いなことに、フォーマットジョブを実行するprintfがあります。
上記の例:
printf "%.12f * 2\n" 3.1e1 | bc -l
またはフロート比較:
n=8.1457413437133669e-02
m=8.1456839223809765e-02
n2=`printf "%.12f" $n`
m2=`printf "%.12f" $m`
if [ $(echo "$n2 > $m2" | bc -l) == 1 ]; then
echo "n is bigger"
else
echo "m is bigger"
fi
OPの配管バージョンは回答を受け入れました
$ echo 3.82955e-5 | sed 's/[eE]+*/\*10\^/'
3.82955*10^-5
OPで受け入れられたsedコマンドに入力をパイプすると、次のような余分な円記号が表示されます。
$ echo 3.82955e-5 | sed 's/[eE]+*/\\*10\\^/'
3.82955\*10\^-5
私は少しハックしてそれを行うことができました。あなたはこのようなことをすることができます-
scientific='4.8844221e+002'
base=$(echo $scientific | cut -d 'e' -f1)
exp=$(($(echo $scientific | cut -d 'e' -f2)*1))
converted=$(bc -l <<< "$base*(10^$exp)")
echo $converted
>> 488.4422100
これを試してください(m4で処理するためのCFD入力データの例でこれを見つけました:)
T0=4e-5
deltaT=2e-6
m4 <<< "esyscmd(perl -e 'printf (${T0} + ${deltaT})')"
これを試してください:(bashを使用して)
printf "scale=20\n0.17879D-13\n" | sed -e 's/D/*10^/' | bc
またはこれ:
num="0.17879D-13"; convert="`printf \"scale=20\n$num\n\" | sed -e 's/D/*10^/' | bc`" ; echo $convert
.00000000000001787900
num="1230.17879"; convert="`printf \"scale=20\n$num\n\" | sed -e 's/D/*10^/' | bc`" ; echo $convert
1230.17879
正の指数がある場合は、これを使用する必要があります。
num="0.17879D+13"; convert="`printf \"scale=20\n$num\n\" | sed -e 's/D+/*10^/' -e 's/D/*10^/' | bc`" ; echo $convert
1787900000000.00000
その最後のものは、それに投げられたすべての数字を処理します。指数として「e」または「E」を含む数値がある場合は、「sed」を適応させることができます。
あなたはあなたが望むスケールを選ぶことができます。