この数が105000000であるとしましょう。この形式では、数値がどれほど大きいかはわかりにくいので、printf
メッセージが表示されたら「科学的」表記を使用しようとします。
% printf "%.3E" 105000000
1.050E+08
これはより良いですが、出力が10の300万、10億、1兆などの二乗形式である「エンジニアリング」表記法を使いたいと思います。
たとえば、次のように書式設定したいとします。
105000 => 105.0E+03 (105 thousand)
105000000 => 105.0E+06 (105 million)
105000000000 => 105.0E+09 (105 billion)
...
これは可能ですかprintf
?
答え1
printf
私はこれができる実装を知りません。printf '%E\n' 123
浮動小数点形式のサポートはオプションであるため、POSIXが完全に機能することを保証することもできません。
さまざまな実装により、次の形式でロケールから千単位の区切り文字を出力printf
できます。%'f
$ LC_NUMERIC=en_GB.UTF-8 printf "%'.0f\n" 105000000
105,000,000
$ LC_NUMERIC=fr_FR.UTF-8 printf "%'.0f\n" 105000000
105 000 000
$ LC_NUMERIC=da_DK.UTF-8 printf "%'.0f\n" 105000000
105.000.000
$ LC_NUMERIC=de_CH.UTF-8 printf "%'.0f\n" 105000000
105'000'000
$ LC_NUMERIC=ps_AF.UTF-8 printf "%'.0f\n" 105000000
105٬000٬000
printf
組み込みを使用すると、K / M / G ...サフィックスとKi / Mi / Giサフィックスksh93
も使用できます。%#d
%#i
$ printf '%#d\n' 105000000 $((2**22))
105M
4.2M
$ printf '%#i\n' 105000000 $((2**22))
100Mi
4.0Mi
(ただし精度は変更できません。たとえば、からの Ki
変換はMi
1024 Kiではなく1000 Kiです。ls -lh
これは、GNU形式(GNUなど)に精通している場合は驚くことがあります。整数その数は2 63 -1(8Ei - 1))と同じです。
手動で実装する方法は次のとおりですzsh
。
eng() {
local n="${(j: :)argv}" exp
zmodload zsh/mathfunc
if ((n)) && ((exp = int(floor(log10(abs(n)) / 3)) * 3)); then
printf '%.10ge%d\n' "n / 1e$exp" exp
else
printf '%.10g\n' "$n"
fi
}
それから:
$ eng 123
123
$ eng 12345
12.345e3
$ eng 0.000000123123
123.123e-9
$ eng 1. / -1234
-810.3727715e-6
他の多くの言語と同様に、zsh
浮動小数点数に関連する演算は浮動小数点演算(プロセッサタイプを使用double
)で実行され、整数のみに関連する演算は整数演算(プロセッサタイプを使用)デバイスタイプとして実行されますlong
。これには次のようないくつかの効果があります。
$ eng 1 / -1234
0
$ eng 1. / -1234
-810.3727715e-6
だけでなく:
$ eng 1 \*{2..28}. # factorial 28
304.8883446e27
$ eng 1 \*{2..28}
-5.968160533e18 # 64bit signed integer overflow
eng
(この機能だけに限られたわけではありませんが)
または、POSIXを使用するPOSIXシェル関数でbc
任意の精度を許可します。
eng() (
IFS=" "
scale=$1; shift
bc -l << EOF |
s = scale = $scale
if (scale < 20) s = 20
n = $*
if (n != 0) {
scale = s
a = n; if (a < 0) a = -a
e = l(a) / l(10) / 3 + 10 ^ -15
if (e < 0) e -= 1
scale = 0
e = e / 1 * 3
scale = s
if (scale <= -e) scale = 1 - e
n = n / 10^e
scale = $scale
}
n/1
if (e != 0) e
EOF
sed '
:1
/\\$/{
N;b1
}
s/\\\n//g
/\./s/0*$//
s/\.$//
$!N
s/\n/e/'
)
(n値(例:0.001)の指数log10(n)を計算すると、丸め誤差をオフセットするために1e-15だけオフセットします。)
ここで、最初のパラメータは次のように処理されます。スケール:
$ eng 2 1/3
330e-3
$ eng 20 1/3
333.33333333333333333e-3
基本的にはエンジニアリング表記を理解していないので、bc
次のように書く必要があります。
$ eng 20 "1.123123 * 10^2000"
112.3123e1998