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))
}
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 {
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 {
/* dp_list := make ([]OTS_DataPoint, intervals_num */
obj = new (OTS_TimeSeries)
- for ;; {
+ for {
var timestamp float64
var rate float64
fmt.Printf ("timestamp = %.3f; rate = %g;\n", timestamp, rate)
- obj.DataPoints = append (obj.DataPoints, OTS_DataPoint{timestamp, rate})
+ obj.AddDataPoint (timestamp, rate)
}
fd.Close ()
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
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
}
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
}
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);
}