I don't know of any printf
implementation that does. Note that POSIX doesn't even guarantee printf '%E\n' 123
to work at all as support for floating point formats is optional.
With several printf
implementations, you can use %'f
to output thousand separators in locales that have one:
$ 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
With the printf
builtin of ksh93
, you can also use %#d
for K/M/G... suffixes and %#i
for Ki/Mi/Gi ones:
$ printf '%#d\n' 105000000 $((2**22))
105M
4.2M
$ printf '%#i\n' 105000000 $((2**22))
100Mi
4.0Mi
(note however that you can't change the precision and the transition from Ki
to Mi
for instance is at 1000 Ki, not 1024 Ki which can be surprising if you're used to the GNU format (like in GNU ls -lh
). It's also limited to integer numbers up to 263-1 (8Ei - 1)).
As to how to implement it by hand, with 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
}
And then:
$ eng 123
123
$ eng 12345
12.345e3
$ eng 0.000000123123
123.123e-9
$ eng 1. / -1234
-810.3727715e-6
Note that in zsh
like in many other languages, operations involving floats are done in floating point arithmetics (with your processor's double
type) while those involving integers only are done in integer arithmetics (with your processor's long
type). That has some implications like:
$ eng 1 / -1234
0
$ eng 1. / -1234
-810.3727715e-6
but also:
$ eng 1 \*{2..28}. # factorial 28
304.8883446e27
$ eng 1 \*{2..28}
-5.968160533e18 # 64bit signed integer overflow
(though that's not specific to that eng
function)
Or as a POSIX shell function using POSIX bc
, so allowing arbitrary precision:
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/'
)
(with a 1e-15 shift to offset rounding errors when calculating log10(n) for the exponent for values of n like 0.001)
Here with the first argument being taken as the scale:
$ eng 2 1/3
330e-3
$ eng 20 1/3
333.33333333333333333e-3
Note that bc
itself doesn't understand the engineering notation, you have to write:
$ eng 20 "1.123123 * 10^2000"
112.3123e1998