ナノ秒精度で日付を取得します。
$ start=$(date '+%s.%N')
...そして印刷してください:
$ echo ${start}
1662664850.030126174
今まではそんなに良くなった。しかし、ランダムに大きな精度でprintfを実行すると、どのような結果が出るのか見てみましょう。
1662664850.0301261739805340766906738281250000000000000000000000000
Q1. dateコマンドは実際に開始変数にその分の情報を入力しますか、それとも数字がゴミですか?
これが質問の2番目の部分です。私がしばらく数学をしたいとしましょう。 「終了」タイムスタンプを作成します。
$ end=$(date '+%s.%N')
$ echo ${end}
1662665413.471669572
$ printf "%.55f\n" ${end}
1662665413.4716695720562711358070373535156250000000000000000000000
ここで、bcを使用して期待される結果を得る。
$ echo $(bc <<< ${end}-${start})
563.441543398
しかし、PythonやPerlを使用したときに得られた結果を見てください。
$ echo $(python -c "print(${end} - ${start})")
563.441543579
$ echo $(perl -e "print(${end} - ${start})")
563.441543579102
ある時点で、この数字は次のように表示されます。
紀元前563.441543398話 Python 563.441543579話 真珠 563.441543579話102
Q2.数値は多様ですが、丸めによる結果は予想されたものとは異なります。何を提供しますか?
システム情報:
Linux 3.10.0-1160.71.1.el7.x86_64#1 SMP 2022年6月15日水曜日08:55:08 UTC
コマンド情報:
日付(GNU coreutils)8.22
bc 1.06.95
Python 2.7.5
Perl 5、バージョン16、Subversion 3(v5.16.3)x86_64-linux-thread-multi用に構築
ベストアンサー1
他の人が言ったように、浮動小数点数のほとんどの10進表現は、コンピュータが計算に使用するバイナリ形式では正確に表現できません。
あなたが見るのは、printf %.55f
元の数字の2進近似を10進数で表したものです。
printf
(可能な)組み込みコマンドはバイナリ表現に変換を使用し、それを関数1662665413.471669572
(またはシリーズの他の関数、たとえば)に渡してフォーマットします(に変更)。long double
strtold()
printf()
snprintf()
%.55f
%.55Lf
表現は、long double
システムごと、Cコンパイラごと、Cコンパイラごと、CPUアーキテクチャによって異なります。 amd64ハードウェアでGNU cc / shellでコンパイルされたGNU / Linuxシステムの場合printf
、long doubleは現在のタイムスタンプをナノ秒精度で保存するのに十分な精度を持ちます。
しかし、ほとんどのawk実装、Perl、ほとんどのシェル(bashではなく浮動小数点演算をサポートする場合)を含む多くの(ほとんどではありませんが)ツールと言語は長いdoubleの代わりにdoubleを使用し、倍精度数字は常に53桁です精度だけがあります。だから、精度は小数点以下15桁を超えることはできません。1.
これが正確なタイムスタンプを扱うほとんどのものが実際にタイムスタンプを2つの整数、つまり秒とマイクロ秒(struct timeval
システムコールから返された値gettimeofday()
)またはナノ秒(struct timespec
システムコールで返された値clock_gettime()
)で表す理由の1つです。
これがGNUが浮動小数点バリアントの代わりにおよびをdate
持ち、zshが浮動小数点の代わりに配列を持つ理由です。%s
%N
%s
$epochtime
これらの高精度タイムスタンプで計算を実行するには、言語/ツールがlong doubleを使用しないか、またはCPU浮動小数点演算(たとえばbc
。
ほとんどのシェルは整数演算に64ビット整数を使用します。long
これは最大9223372036854775807までの数字を受け入れることができます。
たとえば、2つのタイムスタンプ(各タイムスタンプを(秒、ナノ秒)タプルとして表示)の差を計算するには、ナノ秒(sec2 - sec1) * 100000000 + nsec2 - nsec1
単位で差を取得できます。
たとえば、zshでは次のようになります。
zmodload zsh/datetime
start=($epochtime)
uname
end=($epochtime)
print running uname took about $((
(end[1] - start[1]) * 1_000_000_000 + end[2] - start[2] )) nanoseconds.
ここに与えられた:
Linux
running uname took about 2621008 nanoseconds.
埋め込まれていないコマンド(含む)を実行するのに少なくとも数千ナノ秒かかるシェルでは、そのような高精度を持つことは言葉ではないとdate
主張できます。
図:
zmodload zsh/datetime
start=$EPOCHREALTIME
uname
end=$EPOCHREALTIME
printf 'running uname took about %.5g seconds\n' $(( end - start ))
$EPOCHREALTIME
秒とナノ秒(ゼロパディング)整数を中間値に連結して構築されているため、完全な精度がありますが、.
計算を実行するために変換すると一部の精度が失われます。これはおそらく十分です。double
ksh93のように、ここでは次のことをお勧めします。
typeset -F SECONDS=0
uname
printf "running uname took %g seconds\n" $SECONDS
($SECONDS
、シェルが起動してから節約された時間はフローティング(およびストップウォッチにリセット)に設定でき、この場合はマイクロ秒精度を得ることができます。)
1たとえば、a of sの代わりにsをprintf
使用しても同じ数字が提供されるという保証はありません(たとえば、and ofまたはを使用してみてください)。double
long double
printf %.16g <a-16-digit-number>
9.999999999999919
printf
zsh
gawk
perl