11# cython: boundscheck=False, wraparound=False, cdivision=True
2-
32from libc.math cimport (
43 round ,
54 signbit,
65 sqrt,
6+ pow ,
7+ log10,
8+ abs ,
9+ isfinite,
710)
811from libcpp.deque cimport deque
912from libcpp.stack cimport stack
1013from libcpp.unordered_map cimport unordered_map
14+ from libcpp cimport bool
15+
1116
1217from pandas._libs.algos cimport TiebreakEnumType
1318
@@ -21,6 +26,8 @@ from numpy cimport (
2126 ndarray,
2227)
2328
29+
30+
2431cnp.import_array()
2532
2633import cython
@@ -724,6 +731,46 @@ cdef float64_t calc_kurt(int64_t minp, int64_t nobs,
724731
725732 return result
726733
734+ cdef void update_sum_of_window( float64_t val,
735+ float64_t ** x_value,
736+ float64_t ** comp_value,
737+ int power_of_element,
738+ bool add_mode, # 1 for add_kurt, 0 for remove_kurt
739+ ) noexcept nogil:
740+
741+ cdef:
742+ float64_t val_raised, new_sum
743+ bool val_length_flag, x_length_flag
744+
745+ if add_mode:
746+ val_raised = pow (val, power_of_element)
747+ else :
748+ val_raised = - pow (val, power_of_element)
749+
750+ x_length_flag = abs (log10(abs (x_value[0 ][0 ]))) > 15 and isfinite(abs (log10(abs (x_value[0 ][0 ])))) == 1
751+ val_length_flag = abs (log10(abs (val_raised))) > 15 and isfinite(abs (log10(abs (val_raised)))) == 1
752+
753+ # We'll try to maintain comp_value as the counter for
754+ # numbers <1e15 to keep it from getting rounded out.
755+ if x_length_flag and val_length_flag:
756+ # Both > 1e15 or < 1-e15
757+ x_value[0 ][0 ] += val_raised
758+
759+ elif x_length_flag:
760+ comp_value[0 ][0 ] += val_raised
761+
762+
763+ elif val_length_flag:
764+ comp_value[0 ][0 ] += x_value[0 ][0 ]
765+ x_value[0 ][0 ] = val_raised
766+
767+ else :
768+ # Neither are >1e15/<1e-15, safe to proceed
769+ x_value[0 ][0 ] += val_raised
770+
771+ if comp_value[0 ][0 ] != 0 :
772+ x_value[0 ][0 ] += comp_value[0 ][0 ]
773+ comp_value[0 ][0 ] = 0
727774
728775cdef void add_kurt(float64_t val, int64_t * nobs,
729776 float64_t * x, float64_t * xx,
@@ -736,29 +783,15 @@ cdef void add_kurt(float64_t val, int64_t *nobs,
736783 float64_t * prev_value
737784 ) noexcept nogil:
738785 """ add a value from the kurotic calc """
739- cdef:
740- float64_t y, t
741786
742787 # Not NaN
743788 if val == val:
744789 nobs[0 ] = nobs[0 ] + 1
745790
746- y = val - compensation_x[0 ]
747- t = x[0 ] + y
748- compensation_x[0 ] = t - x[0 ] - y
749- x[0 ] = t
750- y = val * val - compensation_xx[0 ]
751- t = xx[0 ] + y
752- compensation_xx[0 ] = t - xx[0 ] - y
753- xx[0 ] = t
754- y = val * val * val - compensation_xxx[0 ]
755- t = xxx[0 ] + y
756- compensation_xxx[0 ] = t - xxx[0 ] - y
757- xxx[0 ] = t
758- y = val * val * val * val - compensation_xxxx[0 ]
759- t = xxxx[0 ] + y
760- compensation_xxxx[0 ] = t - xxxx[0 ] - y
761- xxxx[0 ] = t
791+ update_sum_of_window(val, & x, & compensation_x, 1 , 1 )
792+ update_sum_of_window(val, & xx, & compensation_xx, 2 , 1 )
793+ update_sum_of_window(val, & xxx, & compensation_xxx, 3 , 1 )
794+ update_sum_of_window(val, & xxxx, & compensation_xxxx, 4 , 1 )
762795
763796 # GH#42064, record num of same values to remove floating point artifacts
764797 if val == prev_value[0 ]:
@@ -768,7 +801,6 @@ cdef void add_kurt(float64_t val, int64_t *nobs,
768801 num_consecutive_same_value[0 ] = 1
769802 prev_value[0 ] = val
770803
771-
772804cdef void remove_kurt(float64_t val, int64_t * nobs,
773805 float64_t * x, float64_t * xx,
774806 float64_t * xxx, float64_t * xxxx,
@@ -777,40 +809,25 @@ cdef void remove_kurt(float64_t val, int64_t *nobs,
777809 float64_t * compensation_xxx,
778810 float64_t * compensation_xxxx) noexcept nogil:
779811 """ remove a value from the kurotic calc """
780- cdef:
781- float64_t y, t
782812
783813 # Not NaN
784814 if val == val:
785815 nobs[0 ] = nobs[0 ] - 1
786816
787- y = - val - compensation_x[0 ]
788- t = x[0 ] + y
789- compensation_x[0 ] = t - x[0 ] - y
790- x[0 ] = t
791- y = - val * val - compensation_xx[0 ]
792- t = xx[0 ] + y
793- compensation_xx[0 ] = t - xx[0 ] - y
794- xx[0 ] = t
795- y = - val * val * val - compensation_xxx[0 ]
796- t = xxx[0 ] + y
797- compensation_xxx[0 ] = t - xxx[0 ] - y
798- xxx[0 ] = t
799- y = - val * val * val * val - compensation_xxxx[0 ]
800- t = xxxx[0 ] + y
801- compensation_xxxx[0 ] = t - xxxx[0 ] - y
802- xxxx[0 ] = t
803-
817+ update_sum_of_window(val, & x, & compensation_x, 1 , 0 )
818+ update_sum_of_window(val, & xx, & compensation_xx, 2 , 0 )
819+ update_sum_of_window(val, & xxx, & compensation_xxx, 3 , 0 )
820+ update_sum_of_window(val, & xxxx, & compensation_xxxx, 4 , 0 )
804821
805822def roll_kurt (ndarray[float64_t] values , ndarray[int64_t] start ,
806823 ndarray[int64_t] end , int64_t minp ) -> np.ndarray:
807824 cdef:
808825 Py_ssize_t i , j
809826 float64_t val , mean_val , min_val , sum_val = 0
810- float64_t compensation_xxxx_add , compensation_xxxx_remove
811- float64_t compensation_xxx_remove , compensation_xxx_add
812- float64_t compensation_xx_remove , compensation_xx_add
813- float64_t compensation_x_remove , compensation_x_add
827+ float64_t compensation_xxxx
828+ float64_t compensation_xxx
829+ float64_t compensation_xx
830+ float64_t compensation_x
814831 float64_t x , xx , xxx , xxxx
815832 float64_t prev_value
816833 int64_t nobs , s , e , num_consecutive_same_value
@@ -851,16 +868,16 @@ def roll_kurt(ndarray[float64_t] values, ndarray[int64_t] start,
851868 prev_value = values[s]
852869 num_consecutive_same_value = 0
853870
854- compensation_xxxx_add = compensation_xxxx_remove = 0
855- compensation_xxx_remove = compensation_xxx_add = 0
856- compensation_xx_remove = compensation_xx_add = 0
857- compensation_x_remove = compensation_x_add = 0
871+ compensation_xxxx = 0
872+ compensation_xxx = 0
873+ compensation_xx = 0
874+ compensation_x = 0
858875 x = xx = xxx = xxxx = 0
859876 nobs = 0
860877 for j in range (s, e):
861878 add_kurt(values_copy[j], & nobs, & x, & xx, & xxx, & xxxx,
862- & compensation_x_add , & compensation_xx_add ,
863- & compensation_xxx_add , & compensation_xxxx_add ,
879+ & compensation_x , & compensation_xx ,
880+ & compensation_xxx , & compensation_xxxx ,
864881 & num_consecutive_same_value, & prev_value)
865882
866883 else :
@@ -870,14 +887,14 @@ def roll_kurt(ndarray[float64_t] values, ndarray[int64_t] start,
870887 # calculate deletes
871888 for j in range (start[i - 1 ], s):
872889 remove_kurt(values_copy[j], & nobs, & x, & xx, & xxx, & xxxx,
873- & compensation_x_remove , & compensation_xx_remove ,
874- & compensation_xxx_remove , & compensation_xxxx_remove )
890+ & compensation_x , & compensation_xx ,
891+ & compensation_xxx , & compensation_xxxx )
875892
876893 # calculate adds
877894 for j in range (end[i - 1 ], e):
878895 add_kurt(values_copy[j], & nobs, & x, & xx, & xxx, & xxxx,
879- & compensation_x_add , & compensation_xx_add ,
880- & compensation_xxx_add , & compensation_xxxx_add ,
896+ & compensation_x , & compensation_xx ,
897+ & compensation_xxx , & compensation_xxxx ,
881898 & num_consecutive_same_value, & prev_value)
882899
883900 output[i] = calc_kurt(minp, nobs, x, xx, xxx, xxxx,
0 commit comments