2017-02-09 5 views
2

Ich hatte den Eindruck, dass PostgreSQL halbe Mikrosekunden in Zeitstempeln auf die nächste gerade Mikrosekunde gerundet hat. Z.B .:Wie rundet Postgresql halbe Mikrosekunden in Zeitstempeln?

> 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) 

Dann entdeckte ich, dass:

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

jemand für Zeitstempel den Rundungsalgorithmus verwendet Postgresql Weiß?

Zu Ihrer Information hier ist die Version von Postgresql Ich bin mit:

> 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) 

Antwort

1

All the PostgreSQL time types haben eine Mikrosekunde Auflösung, sechs Dezimalstellen. Das Runden auf die nächste gerade Mikrosekunde wäre keine Mikrosekundenauflösung.

Sein Verhalten sieht im Einklang mit round half-up zu mir, der übliche Weg zu runden. > = 0,5 Runden, sonst Abrunden.

0,5024585 abgerundet Halb bis zu 6 Dezimalstellen aufgerundet auf 0,502459, weil die siebte Ziffer 5.

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

0,5024584999999 Runden bis auf 0,502458 ist, weil die siebte Ziffer 4.

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


Nevermind, erscheint die oben anomale zu sein . Das Durchschreiten von "2000-01-01T00: 00: 00.5024235Z" bis "2000-01-01T00: 00: 00.5024355Z" steht im Einklang mit einer halbgleichen Rundung.

Ich gehe davon aus, dass die Anomalien auf Gleitkommafehler zurückzuführen sind, die von Gleitkomma-Sekunden in der Eingabe in die ganzen Mikrosekunden konvertieren, die timestamp verwendet.

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) 

Dies spielt auch mit interval N microsecond. Weniger Nachkommastellen bedeutet weniger Gleitkommafehler.

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) 

Ein kleines C-Programm bestätigt gibt es ein Gleitkommagenauigkeit Problem mit einfacher Genauigkeit bei 7 Dezimalstellen schwimmt, die Rundung beeinflussen würde.

#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]); 
    } 
} 

Dies erzeugt:

0.50242352 
0.50242448 
0.50242549 
0.50242651 
0.50242752 
0.50242847 
0.50242949 
0.50243050 

Während mit Doppelzimmer, kein Problem.

+0

Definitiv nicht. Ich ging in den Quellcode von PostgreSQL und es verwendet strtod, die zu Double konvertiert. – ifotneak