1 //------------------------------------------------------------------------------ 2 // <copyright file="DoubleStorage.cs" company="Microsoft"> 3 // Copyright (c) Microsoft Corporation. All rights reserved. 4 // </copyright> 5 // <owner current="true" primary="true">Microsoft</owner> 6 // <owner current="true" primary="false">Microsoft</owner> 7 // <owner current="false" primary="false">Microsoft</owner> 8 //------------------------------------------------------------------------------ 9 10 namespace System.Data.Common { 11 using System; 12 using System.Xml; 13 using System.Data.SqlTypes; 14 using System.Collections; 15 16 internal sealed class DoubleStorage : DataStorage { 17 18 private const Double defaultValue = 0.0d; 19 20 private Double[] values; 21 DoubleStorage(DataColumn column)22 internal DoubleStorage(DataColumn column) 23 : base(column, typeof(Double), defaultValue, StorageType.Double) { 24 } 25 Aggregate(int[] records, AggregateType kind)26 override public Object Aggregate(int[] records, AggregateType kind) { 27 bool hasData = false; 28 try { 29 switch (kind) { 30 case AggregateType.Sum: 31 Double sum = defaultValue; 32 foreach (int record in records) { 33 if (IsNull(record)) 34 continue; 35 checked { sum += values[record];} 36 hasData = true; 37 } 38 if (hasData) { 39 return sum; 40 } 41 return NullValue; 42 43 case AggregateType.Mean: 44 Double meanSum = (Double)defaultValue; 45 int meanCount = 0; 46 foreach (int record in records) { 47 if (IsNull(record)) 48 continue; 49 checked { meanSum += (Double)values[record];} 50 meanCount++; 51 hasData = true; 52 } 53 if (hasData) { 54 Double mean; 55 checked {mean = (Double)(meanSum / meanCount);} 56 return mean; 57 } 58 return NullValue; 59 60 case AggregateType.Var: 61 case AggregateType.StDev: 62 int count = 0; 63 double var = (double)defaultValue; 64 double prec = (double)defaultValue; 65 double dsum = (double)defaultValue; 66 double sqrsum = (double)defaultValue; 67 68 foreach (int record in records) { 69 if (IsNull(record)) 70 continue; 71 dsum += (double)values[record]; 72 sqrsum += (double)values[record]*(double)values[record]; 73 count++; 74 } 75 76 if (count > 1) { 77 var = ((double)count * sqrsum - (dsum * dsum)); 78 prec = var / (dsum * dsum); 79 80 // we are dealing with the risk of a cancellation error 81 // double is guaranteed only for 15 digits so a difference 82 // with a result less than 1e-15 should be considered as zero 83 84 if ((prec < 1e-15) || (var <0)) 85 var = 0; 86 else 87 var = var / (count * (count -1)); 88 89 if (kind == AggregateType.StDev) { 90 return Math.Sqrt(var); 91 } 92 return var; 93 } 94 return NullValue; 95 96 case AggregateType.Min: 97 Double min = Double.MaxValue; 98 for (int i = 0; i < records.Length; i++) { 99 int record = records[i]; 100 if (IsNull(record)) 101 continue; 102 min=Math.Min(values[record], min); 103 hasData = true; 104 } 105 if (hasData) { 106 return min; 107 } 108 return NullValue; 109 110 case AggregateType.Max: 111 Double max = Double.MinValue; 112 for (int i = 0; i < records.Length; i++) { 113 int record = records[i]; 114 if (IsNull(record)) 115 continue; 116 max=Math.Max(values[record], max); 117 hasData = true; 118 } 119 if (hasData) { 120 return max; 121 } 122 return NullValue; 123 124 case AggregateType.First: 125 if (records.Length > 0) { 126 return values[records[0]]; 127 } 128 return null; 129 130 case AggregateType.Count: 131 return base.Aggregate(records, kind); 132 133 } 134 } 135 catch (OverflowException) { 136 throw ExprException.Overflow(typeof(Double)); 137 } 138 throw ExceptionBuilder.AggregateException(kind, DataType); 139 } 140 Compare(int recordNo1, int recordNo2)141 override public int Compare(int recordNo1, int recordNo2) { 142 Double valueNo1 = values[recordNo1]; 143 Double valueNo2 = values[recordNo2]; 144 145 if (valueNo1 == defaultValue || valueNo2 == defaultValue) { 146 int bitCheck = CompareBits(recordNo1, recordNo2); 147 if (0 != bitCheck) 148 return bitCheck; 149 } 150 return valueNo1.CompareTo(valueNo2); // not simple, checks Nan 151 } 152 CompareValueTo(int recordNo, object value)153 public override int CompareValueTo(int recordNo, object value) { 154 System.Diagnostics.Debug.Assert(0 <= recordNo, "Invalid record"); 155 System.Diagnostics.Debug.Assert(null != value, "null value"); 156 157 if (NullValue == value) { 158 if (IsNull(recordNo)) { 159 return 0; 160 } 161 return 1; 162 } 163 164 Double valueNo1 = values[recordNo]; 165 if ((defaultValue == valueNo1) && IsNull(recordNo)) { 166 return -1; 167 } 168 return valueNo1.CompareTo((Double)value); 169 } 170 ConvertValue(object value)171 public override object ConvertValue(object value) { 172 if (NullValue != value) { 173 if (null != value) { 174 value = ((IConvertible)value).ToDouble(FormatProvider); 175 } 176 else { 177 value = NullValue; 178 } 179 } 180 return value; 181 } 182 Copy(int recordNo1, int recordNo2)183 override public void Copy(int recordNo1, int recordNo2) { 184 CopyBits(recordNo1, recordNo2); 185 values[recordNo2] = values[recordNo1]; 186 } 187 Get(int record)188 override public Object Get(int record) { 189 Double value = values[record]; 190 if (value != defaultValue) { 191 return value; 192 } 193 return GetBits(record); 194 } 195 Set(int record, Object value)196 override public void Set(int record, Object value) { 197 System.Diagnostics.Debug.Assert(null != value, "null value"); 198 if (NullValue == value) { 199 values[record] = defaultValue; 200 SetNullBit(record, true); 201 } 202 else { 203 values[record] = ((IConvertible)value).ToDouble(FormatProvider); 204 SetNullBit(record, false); 205 } 206 } 207 SetCapacity(int capacity)208 override public void SetCapacity(int capacity) { 209 Double[] newValues = new Double[capacity]; 210 if (null != values) { 211 Array.Copy(values, 0, newValues, 0, Math.Min(capacity, values.Length)); 212 } 213 values = newValues; 214 base.SetCapacity(capacity); 215 } 216 ConvertXmlToObject(string s)217 override public object ConvertXmlToObject(string s) { 218 return XmlConvert.ToDouble(s); 219 } 220 ConvertObjectToXml(object value)221 override public string ConvertObjectToXml(object value) { 222 return XmlConvert.ToString((Double) value); 223 } 224 GetEmptyStorage(int recordCount)225 override protected object GetEmptyStorage(int recordCount) { 226 return new Double[recordCount]; 227 } 228 CopyValue(int record, object store, BitArray nullbits, int storeIndex)229 override protected void CopyValue(int record, object store, BitArray nullbits, int storeIndex) { 230 Double[] typedStore = (Double[]) store; 231 typedStore[storeIndex] = values[record]; 232 nullbits.Set(storeIndex, IsNull(record)); 233 } 234 SetStorage(object store, BitArray nullbits)235 override protected void SetStorage(object store, BitArray nullbits) { 236 values = (Double[]) store; 237 SetNullStorage(nullbits); 238 } 239 } 240 } 241