假设我有这个数字:105000000,在这种形式中我无法轻易看出它有多大,因此printf
在提示时我尝试使用“科学”符号:
% printf "%.3E" 105000000
1.050E+08
这更好,但我想使用“工程”符号,其中输出的格式为 10 3百万、十亿、万亿等的幂。
例如,我想将其格式化为如下所示:
105000 => 105.0E+03 (105 thousand)
105000000 => 105.0E+06 (105 million)
105000000000 => 105.0E+09 (105 billion)
...
可以printf
这样做吗?
答案1
我不知道有任何printf
实现可以做到这一点。请注意,POSIX 甚至不保证printf '%E\n' 123
完全正常工作,因为对浮点格式的支持是可选的。
通过多种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
内置的ksh93
,您还可以使用%#d
K/M/G... 后缀和%#i
Ki/Mi/Gi 后缀:
$ printf '%#d\n' 105000000 $((2**22))
105M
4.2M
$ printf '%#i\n' 105000000 $((2**22))
100Mi
4.0Mi
(但请注意,您无法更改精度,例如从 Ki
到 的过渡Mi
是 1000 Ki,而不是 1024 Ki,如果您习惯了 GNU 格式(例如 GNU ls -lh
),这可能会令人惊讶。它也仅限于整数数字高达 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 shell 函数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