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

관련 정보