タイムスタンプ (秒の小数部のみ) をナノ秒 (10^-9 秒単位) から NTP タイムスタンプの下半分 (2^-32 秒単位) に再スケーリングしようとしています。事実上、これは 4.2949673 を掛けることを意味します。しかし、浮動小数点演算や 32 ビットを超える整数を使用せずにそれを行う必要があります (実際、これは実際には 8 ビット マイクロコントローラー用に書いているため、32 ビット演算でさえ、特に除算ではコストがかかります)。
かなりうまく機能するいくつかのアルゴリズムを思いつきましたが、数値的方法に実際の根拠がないため、それらを改善する方法、またはより正確で他のアルゴリズムに関する提案をいただければ幸いです。 /またはより高速。
アルゴリズム 1
uint32_t intts = (ns >> 16) * 281474 + (ns << 16) / 15259 + ns / 67078;
最初の 2 つの定数は、正しい数値をオーバーシュートするのではなく、わずかにアンダーシュートするように選択され、最終的な係数 67078 はこれを修正するために経験的に決定されました。正しい値の +/- 4 NTP 単位内の結果を生成します。これは +/- 1 ns です。許容範囲ですが、残差はns
. 別の用語を追加できると思います。
アルゴリズム 2
uint32_t ns2 = (2 * ns) + 1;
uint32_t intts = (ns2 << 1)
+ (ns2 >> 3) + (ns2 >> 6) + (ns2 >> 8) + (ns2 >> 9) + (ns2 >> 10)
+ (ns2 >> 16) + (ns2 >> 18) + (ns2 >> 19) + (ns2 >> 20) + (ns2 >> 21)
+ (ns2 >> 22) + (ns2 >> 24) + (ns2 >> 30) + 3;
4.2949673 の 2 進展開に基づいています (実際には 2.14748365 の 2 進展開に基づいています。これは、丸めを行うために 2 倍にして 1 を追加することから始めているためです)。おそらくアルゴリズム 1 よりも高速です (まだベンチマークを取得していません)。+3 は、すべての下位ビットを切り捨てることによるアンダーシュートを相殺するために経験的に決定されましたが、可能な限り最善の仕事をするわけではありません。