2017-02-09 4 views
2

私は、PostgreSQLがタイムスタンプの半マイクロ秒を最も近い偶数マイクロ秒に丸めたという印象を受けました。Postgresqlはタイムスタンプの半分のマイクロ秒をどのように丸めますか?

> select '2000-01-01T00:00:00.5024585Z'::timestamptz; 
      timestamptz   
------------------------------- 
2000-01-01 01:00:00.502459+01 
(1 row) 

誰がPostgreSQLは、タイムスタンプのために使用する丸めアルゴリズムを知っています:例えば:

> select '2000-01-01T00:00:00.0000585Z'::timestamptz; 
      timestamptz   
------------------------------- 
2000-01-01 01:00:00.000058+01 
(1 row) 

> select '2000-01-01T00:00:00.0000575Z'::timestamptz; 
      timestamptz   

------------------------------- 
2000-01-01 01:00:00.000058+01 
(1 row) 

それから私はことを発見しましたか?あなたの情報については

は、ここで私が実行しているのPostgreSQLのバージョンがあります:

> select version(); 
               version              
---------------------------------------------------------------------------------------------------------------- 
PostgreSQL 9.6.1 on x86_64-apple-darwin15.6.0, compiled by Apple LLVM version 8.0.0 (clang-800.0.42.1), 64-bit 
(1 row) 

答えて

1

All the PostgreSQL time types、小数点以下6桁をマイクロ秒の分解能を持っています。 最も近い偶数マイクロ秒に丸めても、マイクロ秒の解像度ではありません。

その動作は、私には普通の方法であるround half-upと一貫しています。 > = 0.5は切り上げ、それ以外は切り捨てる。 7桁目が5

test=# select '2000-01-01T00:00:00.5024585Z'::timestamp; 
     timestamp   
---------------------------- 
2000-01-01 00:00:00.502459 
(1 row) 

0.5024584999999 0.502458までのラウンドであるため、7桁目が4

test=# select '2000-01-01T00:00:00.5024584999999Z'::timestamp; 
     timestamp   
---------------------------- 
2000-01-01 00:00:00.502458 
(1 row) 

あるので

0.5024585小数点以下6桁に丸めハーフアップは0.502459までの丸め


上記のことは異常であるようです。 '2000-01-01T00:00:00.5024235Z'から '2000-01-01T00:00:00.5024355Z'にステップインすることは、ハーフ偶数丸めと一貫しています。

私は、入力の浮動小数点秒から浮動小数点エラーへの変換が、timestampが使用する整数マイクロ秒に変換されているためと推測しています。

test=# select '2000-01-01T00:00:00.5024235Z'::timestamp; 
     timestamp   
---------------------------- 
2000-01-01 00:00:00.502424 
(1 row) 

test=# select '2000-01-01T00:00:00.5024245Z'::timestamp; 
     timestamp   
---------------------------- 
2000-01-01 00:00:00.502425 
(1 row) 

test=# select '2000-01-01T00:00:00.5024255Z'::timestamp; 
     timestamp   
---------------------------- 
2000-01-01 00:00:00.502425 
(1 row) 

test=# select '2000-01-01T00:00:00.5024265Z'::timestamp; 
     timestamp   
---------------------------- 
2000-01-01 00:00:00.502426 
(1 row) 

test=# select '2000-01-01T00:00:00.5024275Z'::timestamp; 
     timestamp   
---------------------------- 
2000-01-01 00:00:00.502428 
(1 row) 

test=# select '2000-01-01T00:00:00.5024285Z'::timestamp; 
     timestamp   
---------------------------- 
2000-01-01 00:00:00.502428 
(1 row) 

test=# select '2000-01-01T00:00:00.5024295Z'::timestamp; 
     timestamp   
--------------------------- 
2000-01-01 00:00:00.50243 
(1 row) 

test=# select '2000-01-01T00:00:00.5024305Z'::timestamp; 
     timestamp   
--------------------------- 
2000-01-01 00:00:00.50243 
(1 row) 

test=# select '2000-01-01T00:00:00.5024315Z'::timestamp; 
     timestamp   
---------------------------- 
2000-01-01 00:00:00.502432 
(1 row) 

test=# select '2000-01-01T00:00:00.5024325Z'::timestamp; 
     timestamp   
---------------------------- 
2000-01-01 00:00:00.502432 
(1 row) 

test=# select '2000-01-01T00:00:00.5024335Z'::timestamp; 
     timestamp   
---------------------------- 
2000-01-01 00:00:00.502434 
(1 row) 

test=# select '2000-01-01T00:00:00.5024345Z'::timestamp; 
     timestamp   
---------------------------- 
2000-01-01 00:00:00.502434 
(1 row) 

test=# select '2000-01-01T00:00:00.5024355Z'::timestamp; 
     timestamp   
---------------------------- 
2000-01-01 00:00:00.502436 
(1 row) 

これはまた、interval N microsecondで再生されます。小数点以下の桁数が少ないほど浮動小数点エラーが少なくなります。

test=# select interval '0.5 microsecond'; 
interval 
---------- 
00:00:00 
(1 row) 

test=# select interval '1.5 microsecond'; 
    interval  
----------------- 
00:00:00.000002 
(1 row) 

test=# select interval '2.5 microsecond'; 
    interval  
----------------- 
00:00:00.000002 
(1 row) 

test=# select interval '3.5 microsecond'; 
    interval  
----------------- 
00:00:00.000004 
(1 row) 

test=# select interval '4.5 microsecond'; 
    interval  
----------------- 
00:00:00.000004 
(1 row) 

test=# select interval '5.5 microsecond'; 
    interval  
----------------- 
00:00:00.000006 
(1 row) 

test=# select interval '6.5 microsecond'; 
    interval  
----------------- 
00:00:00.000006 
(1 row) 

小さなCプログラムでは、丸め影響を与える7つの小数点以下の桁数での単精度浮動小数点数と浮動小数点の精度に問題があると確認しました。

#include <math.h> 
#include <stdio.h> 

int main() { 
    float nums[] = { 
     0.5024235f, 
     0.5024245f, 
     0.5024255f, 
     0.5024265f, 
     0.5024275f, 
     0.5024285f, 
     0.5024295f, 
     0.5024305f, 
     NAN 
    }; 

    for(int i = 0; !isnan(nums[i]); i++) { 
     printf("%0.8f\n", nums[i]); 
    } 
} 

これが生成します。

0.50242352 
0.50242448 
0.50242549 
0.50242651 
0.50242752 
0.50242847 
0.50242949 
0.50243050 

ダブルスとのに対し、全く問題ありません。

0.50242350 
0.50242450 
0.50242550 
0.50242650 
0.50242750 
0.50242850 
0.50242950 
0.50243050 
+0

間違いなく。私はPostgreSQLのソースコードを調べて、二重に変換するstrtodを使用します。 – ifotneak

関連する問題