From: Florian Forster Date: Tue, 7 Jun 2011 20:54:43 +0000 (+0200) Subject: OTS_TimeSeries: Add the AddDataPoint() method. X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=977787ef46f4aa56ab39b331ecd0969decd701df;p=otsdb-go.git OTS_TimeSeries: Add the AddDataPoint() method. --- diff --git a/ots_timeseries.go b/ots_timeseries.go index efa8931..fd22468 100644 --- a/ots_timeseries.go +++ b/ots_timeseries.go @@ -16,6 +16,11 @@ type OTS_TimeSeries struct { DataPoints []OTS_DataPoint } +func timestampToInterval (a float64, b float64) float64 { + tmp := int (a / b) + return b * float64 (tmp) +} + /* Functions for the sort interface. */ func (obj *OTS_TimeSeries) Len () int { return (len (obj.DataPoints)) @@ -29,14 +34,7 @@ func (obj *OTS_TimeSeries) Less (i, j int) bool { } func (obj *OTS_TimeSeries) Swap (i, j int) { - tmp := obj.DataPoints[i] - obj.DataPoints[i] = obj.DataPoints[j] - obj.DataPoints[j] = tmp -} - -func Fmod64 (a float64, b float64) float64 { - tmp := int (a / b) - return b * float64 (tmp) + obj.DataPoints[i], obj.DataPoints[j] = obj.DataPoints[j], obj.DataPoints[i] } func (obj *OTS_TimeSeries) Write (name string) os.Error { @@ -56,6 +54,45 @@ func (obj *OTS_TimeSeries) Write (name string) os.Error { return nil } +func (obj *OTS_TimeSeries) AddDataPoint (timestamp, rate float64) int { + if math.IsNaN (timestamp) || (timestamp < 0.0) { + return -1 + } + + /* Handle the usual case first. */ + if (timestamp > obj.TimestampLast ()) || (obj.DataPoints == nil) { + obj.DataPoints = append (obj.DataPoints, OTS_DataPoint{timestamp, rate}) + return 0 + } + + /* Find the first index where the timestamp is greater than or equal to the + * new timestamp. This is an O(log n) operation. */ + index := sort.Search (len (obj.DataPoints), func (i int) bool { + if obj.DataPoints[i].TimeStamp >= timestamp { + return true + } + return false + }) + + /* Check for a duplicate time. */ + if obj.DataPoints[index].TimeStamp == timestamp { + obj.DataPoints[index].Rate = rate + return 0 + } + + /* Insert the new datapoint at "index". Currently, this is a O(n) operation. + * First, add the new datapoint at the end. */ + obj.DataPoints = append (obj.DataPoints, OTS_DataPoint{timestamp, rate}) + /* Now move the datapoint to the position "index". */ + for i := len (obj.DataPoints) - 2; i >= index; i-- { + /* TODO: Is there a faster way to manipulate arrays in Go than to move + * elements in bubblesort fashion? */ + obj.Swap (i, i + 1) + } + + return 0 +} + func ReadFile (name string) (obj *OTS_TimeSeries, err os.Error) { fd, err := os.Open (name) if err != nil { @@ -65,7 +102,7 @@ func ReadFile (name string) (obj *OTS_TimeSeries, err os.Error) { /* dp_list := make ([]OTS_DataPoint, intervals_num */ obj = new (OTS_TimeSeries) - for ;; { + for { var timestamp float64 var rate float64 @@ -78,7 +115,7 @@ func ReadFile (name string) (obj *OTS_TimeSeries, err os.Error) { fmt.Printf ("timestamp = %.3f; rate = %g;\n", timestamp, rate) - obj.DataPoints = append (obj.DataPoints, OTS_DataPoint{timestamp, rate}) + obj.AddDataPoint (timestamp, rate) } fd.Close () @@ -157,6 +194,20 @@ func (obj *OTS_TimeSeries) ConsolidatePointAverage (ts_start, ts_end float64) OT return dp } /* ConsolidatePointAverage */ +func (obj *OTS_TimeSeries) TimestampFirst () float64 { + if obj.DataPoints == nil { + return math.NaN () + } + return obj.DataPoints[0].TimeStamp +} + +func (obj *OTS_TimeSeries) TimestampLast () float64 { + if obj.DataPoints == nil { + return math.NaN () + } + return obj.DataPoints[len (obj.DataPoints) - 1].TimeStamp +} + func (obj *OTS_TimeSeries) ConsolidateAverage (interval float64) *OTS_TimeSeries { if interval <= 0.0 { return nil @@ -169,8 +220,8 @@ func (obj *OTS_TimeSeries) ConsolidateAverage (interval float64) *OTS_TimeSeries ts_raw_first, ts_raw_last) /* Determine the timespan the consolidated data will span. */ - ts_csl_first := Fmod64 (ts_raw_first, interval) - ts_csl_last := Fmod64 (ts_raw_last, interval) + ts_csl_first := timestampToInterval (ts_raw_first, interval) + ts_csl_last := timestampToInterval (ts_raw_last, interval) if ts_csl_first < ts_raw_first { ts_csl_first += interval } diff --git a/ots_timeseries_test.go b/ots_timeseries_test.go index 8df850e..8b69eb8 100644 --- a/ots_timeseries_test.go +++ b/ots_timeseries_test.go @@ -45,7 +45,7 @@ var consolidatePointAverageTests = []consolidatePointAverageTest { consolidatePointAverageTest{27.0, 7.0, 5.1}, } -func FloatsDiffer (a, b float64) bool { +func floatsDiffer (a, b float64) bool { if math.Fabs (a - b) > 1.0e-6 { return true } @@ -60,7 +60,7 @@ func TestConsolidatePointAverage (t *testing.T) { testCase := consolidatePointAverageTests[i] dp := obj.ConsolidatePointAverage (testCase.tsStart, testCase.tsEnd); - if FloatsDiffer (dp.Rate, testCase.rate) { + if floatsDiffer (dp.Rate, testCase.rate) { t.Errorf ("ConsolidatePointAverage (%g, %g) failed: Expected %g, got %g", testCase.tsStart, testCase.tsEnd, testCase.rate, dp.Rate); }