printfに数値の「エンジニアリング」表現形式はありますか?

printfに数値の「エンジニアリング」表現形式はありますか?

この数が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変換はMi1024 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

おすすめ記事