1 //------------------------------------------------------------------------------
2 // <copyright file="SqlDecimal.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">junfang</owner>
6 // <owner current="true" primary="false">Microsoft</owner>
7 // <owner current="true" primary="false">Microsoft</owner>
8 // <owner current="true" primary="false">Microsoft</owner>
9 //------------------------------------------------------------------------------
11 //**************************************************************************
12 // @File: SqlNumeric.cs
17 // Purpose: Implementation of SqlMoney which is equivalent to
18 // data type "numeric" and "decimal" in SQL Server
25 // 118776 JXF 09/17/02 Double to SqlDecimal/SqlMoney conversion
26 // 102740 BDS 03/28/02 UDT Serialization
27 // 86121 AZA 08/21/01 Stop accessing Precision and Scale on null SqlDecimal
30 // 09/17/99 JunFang Created and implemented as first drop.
33 //**************************************************************************
36 using System.Data.Common;
37 using System.Diagnostics;
38 using System.Globalization;
39 using System.Runtime.InteropServices;
41 using System.Xml.Schema;
42 using System.Xml.Serialization;
44 namespace System.Data.SqlTypes {
48 /// Represents a fixed precision and scale numeric value between -10<superscript term='38'/>
49 /// -1 and 10<superscript term='38'/> -1 to be stored in or retrieved from a database.
53 [StructLayout(LayoutKind.Sequential)]
54 [XmlSchemaProvider("GetXsdType")]
55 public struct SqlDecimal : INullable, IComparable, IXmlSerializable {
56 // data in CSsNumeric in SQL Server
57 // BYTE m_cbLen; // # of DWORDs + 1 (1 is for sign)
58 // BYTE m_bPrec; // precision
59 // BYTE m_bScale; // scale
60 // BYTE m_bSign; // NUM_POSITIVE or NUM_NEGATIVE
61 // ULONG m_rgulData [x_culNumeMax];
63 internal byte m_bStatus; // bit 0: fNotNull, bit 1: fNegative
64 internal byte m_bLen; // number of uints used, = (CSsNumeric.m_cbLen - 1) / 4.
65 internal byte m_bPrec;
66 internal byte m_bScale;
67 internal UInt32 m_data1;
68 internal UInt32 m_data2;
69 internal UInt32 m_data3;
70 internal UInt32 m_data4;
72 private static readonly byte NUMERIC_MAX_PRECISION = 38; // Maximum precision of numeric
74 /// <para>[To be supplied.]</para>
76 public static readonly byte MaxPrecision = NUMERIC_MAX_PRECISION; // max SS precision
78 /// <para>[To be supplied.]</para>
80 public static readonly byte MaxScale = NUMERIC_MAX_PRECISION; // max SS scale
82 private static readonly byte x_bNullMask = 1; // bit mask for null bit in m_bStatus
83 private static readonly byte x_bIsNull = 0; // is null
84 private static readonly byte x_bNotNull = 1; // is not null
85 private static readonly byte x_bReverseNullMask = unchecked((byte)~x_bNullMask);
87 private static readonly byte x_bSignMask = 2; // bit mask for sign bit in m_bStatus
88 private static readonly byte x_bPositive = 0; // is positive
89 private static readonly byte x_bNegative = 2; // is negative
90 private static readonly byte x_bReverseSignMask = unchecked((byte)~x_bSignMask);
92 private static readonly uint x_uiZero = (uint) 0;
94 private static readonly int x_cNumeMax = 4;
95 private static readonly long x_lInt32Base = ((long)1) << 32; // 2**32
96 private static readonly ulong x_ulInt32Base = ((ulong)1) << 32; // 2**32
97 private static readonly ulong x_ulInt32BaseForMod = x_ulInt32Base - 1; // 2**32 - 1 (0xFFF...FF)
99 internal static readonly ulong x_llMax = Int64.MaxValue; // Max of Int64
101 private static readonly uint x_ulBase10 = 10;
103 private static readonly double DUINT_BASE = (double)x_lInt32Base; // 2**32
104 private static readonly double DUINT_BASE2 = DUINT_BASE * DUINT_BASE; // 2**64
105 private static readonly double DUINT_BASE3 = DUINT_BASE2 * DUINT_BASE; // 2**96
106 private static readonly double DMAX_NUME = 1.0e+38; // Max value of numeric
107 private static readonly uint DBL_DIG = 17; // Max decimal digits of double
109 private static readonly byte x_cNumeDivScaleMin = 6; // Minimum result scale of numeric division
111 // Array of multipliers for lAdjust and Ceiling/Floor.
112 private static readonly uint[] x_rgulShiftBase = new uint[9] {
117 10 * 10 * 10 * 10 * 10,
118 10 * 10 * 10 * 10 * 10 * 10,
119 10 * 10 * 10 * 10 * 10 * 10 * 10,
120 10 * 10 * 10 * 10 * 10 * 10 * 10 * 10,
121 10 * 10 * 10 * 10 * 10 * 10 * 10 * 10 * 10
124 #region DecimalHelperTableGenerator
126 // the code below will generate the DecimalHelpers tables
127 static private string[] HelperNames = {
128 "DecimalHelpersLo", "DecimalHelpersMid", "DecimalHelpersHi", "DecimalHelpersHiHi",
132 static private void DumpDecimalHelperParts(int index)
134 SqlDecimal sqlDecimalValue = 10; // start precision=2
136 Console.WriteLine("static private readonly UInt32[] {0} = {{", HelperNames[index]);
137 for (int precision = 2; precision <= SqlDecimal.MaxPrecision; precision++){
138 Console.WriteLine(" 0x{0,8:x8}, // precision:{1}, value:{2}", sqlDecimalValue.Data[index], precision, sqlDecimalValue.ToString());
139 if (precision < SqlDecimal.MaxPrecision){
140 sqlDecimalValue *= 10;
143 sqlDecimalValue = SqlDecimal.MaxValue;
144 int[] data = sqlDecimalValue.Data;
145 UInt32[] udata = { (UInt32)data[0], (UInt32)data[1], (UInt32)data[2], (UInt32)data[3]};
147 for (int i = 0; i < 4; i++){
149 carry = (++udata[i] == 0);
152 Console.WriteLine(" 0x{0,8:x8}, // precision:{1}+1, value:{2}+1", udata[index], SqlDecimal.MaxPrecision, SqlDecimal.MaxValue.ToString());
154 Console.WriteLine("};");
159 static public void CreateDecimalHelperTable()
161 for (int i = 0; i < 4; i++)
163 DumpDecimalHelperParts(i);
170 #region DecimalHelperTable
171 static private readonly UInt32[] DecimalHelpersLo = {
172 0x0000000a, // precision:2, value:10
173 0x00000064, // precision:3, value:100
174 0x000003e8, // precision:4, value:1000
175 0x00002710, // precision:5, value:10000
176 0x000186a0, // precision:6, value:100000
177 0x000f4240, // precision:7, value:1000000
178 0x00989680, // precision:8, value:10000000
179 0x05f5e100, // precision:9, value:100000000
180 0x3b9aca00, // precision:10, value:1000000000
181 0x540be400, // precision:11, value:10000000000
182 0x4876e800, // precision:12, value:100000000000
183 0xd4a51000, // precision:13, value:1000000000000
184 0x4e72a000, // precision:14, value:10000000000000
185 0x107a4000, // precision:15, value:100000000000000
186 0xa4c68000, // precision:16, value:1000000000000000
187 0x6fc10000, // precision:17, value:10000000000000000
188 0x5d8a0000, // precision:18, value:100000000000000000
189 0xa7640000, // precision:19, value:1000000000000000000
190 0x89e80000, // precision:20, value:10000000000000000000
191 0x63100000, // precision:21, value:100000000000000000000
192 0xdea00000, // precision:22, value:1000000000000000000000
193 0xb2400000, // precision:23, value:10000000000000000000000
194 0xf6800000, // precision:24, value:100000000000000000000000
195 0xa1000000, // precision:25, value:1000000000000000000000000
196 0x4a000000, // precision:26, value:10000000000000000000000000
197 0xe4000000, // precision:27, value:100000000000000000000000000
198 0xe8000000, // precision:28, value:1000000000000000000000000000
199 0x10000000, // precision:29, value:10000000000000000000000000000
200 0xa0000000, // precision:30, value:100000000000000000000000000000
201 0x40000000, // precision:31, value:1000000000000000000000000000000
202 0x80000000, // precision:32, value:10000000000000000000000000000000
203 0x00000000, // precision:33, value:100000000000000000000000000000000
204 0x00000000, // precision:34, value:1000000000000000000000000000000000
205 0x00000000, // precision:35, value:10000000000000000000000000000000000
206 0x00000000, // precision:36, value:100000000000000000000000000000000000
207 0x00000000, // precision:37, value:1000000000000000000000000000000000000
208 0x00000000, // precision:38, value:10000000000000000000000000000000000000
209 0x00000000, // precision:38+1, value:99999999999999999999999999999999999999+1
212 static private readonly UInt32[] DecimalHelpersMid = {
213 0x00000000, // precision:2, value:10
214 0x00000000, // precision:3, value:100
215 0x00000000, // precision:4, value:1000
216 0x00000000, // precision:5, value:10000
217 0x00000000, // precision:6, value:100000
218 0x00000000, // precision:7, value:1000000
219 0x00000000, // precision:8, value:10000000
220 0x00000000, // precision:9, value:100000000
221 0x00000000, // precision:10, value:1000000000
222 0x00000002, // precision:11, value:10000000000
223 0x00000017, // precision:12, value:100000000000
224 0x000000e8, // precision:13, value:1000000000000
225 0x00000918, // precision:14, value:10000000000000
226 0x00005af3, // precision:15, value:100000000000000
227 0x00038d7e, // precision:16, value:1000000000000000
228 0x002386f2, // precision:17, value:10000000000000000
229 0x01634578, // precision:18, value:100000000000000000
230 0x0de0b6b3, // precision:19, value:1000000000000000000
231 0x8ac72304, // precision:20, value:10000000000000000000
232 0x6bc75e2d, // precision:21, value:100000000000000000000
233 0x35c9adc5, // precision:22, value:1000000000000000000000
234 0x19e0c9ba, // precision:23, value:10000000000000000000000
235 0x02c7e14a, // precision:24, value:100000000000000000000000
236 0x1bcecced, // precision:25, value:1000000000000000000000000
237 0x16140148, // precision:26, value:10000000000000000000000000
238 0xdcc80cd2, // precision:27, value:100000000000000000000000000
239 0x9fd0803c, // precision:28, value:1000000000000000000000000000
240 0x3e250261, // precision:29, value:10000000000000000000000000000
241 0x6d7217ca, // precision:30, value:100000000000000000000000000000
242 0x4674edea, // precision:31, value:1000000000000000000000000000000
243 0xc0914b26, // precision:32, value:10000000000000000000000000000000
244 0x85acef81, // precision:33, value:100000000000000000000000000000000
245 0x38c15b0a, // precision:34, value:1000000000000000000000000000000000
246 0x378d8e64, // precision:35, value:10000000000000000000000000000000000
247 0x2b878fe8, // precision:36, value:100000000000000000000000000000000000
248 0xb34b9f10, // precision:37, value:1000000000000000000000000000000000000
249 0x00f436a0, // precision:38, value:10000000000000000000000000000000000000
250 0x098a2240, // precision:38+1, value:99999999999999999999999999999999999999+1
253 static private readonly UInt32[] DecimalHelpersHi = {
254 0x00000000, // precision:2, value:10
255 0x00000000, // precision:3, value:100
256 0x00000000, // precision:4, value:1000
257 0x00000000, // precision:5, value:10000
258 0x00000000, // precision:6, value:100000
259 0x00000000, // precision:7, value:1000000
260 0x00000000, // precision:8, value:10000000
261 0x00000000, // precision:9, value:100000000
262 0x00000000, // precision:10, value:1000000000
263 0x00000000, // precision:11, value:10000000000
264 0x00000000, // precision:12, value:100000000000
265 0x00000000, // precision:13, value:1000000000000
266 0x00000000, // precision:14, value:10000000000000
267 0x00000000, // precision:15, value:100000000000000
268 0x00000000, // precision:16, value:1000000000000000
269 0x00000000, // precision:17, value:10000000000000000
270 0x00000000, // precision:18, value:100000000000000000
271 0x00000000, // precision:19, value:1000000000000000000
272 0x00000000, // precision:20, value:10000000000000000000
273 0x00000005, // precision:21, value:100000000000000000000
274 0x00000036, // precision:22, value:1000000000000000000000
275 0x0000021e, // precision:23, value:10000000000000000000000
276 0x0000152d, // precision:24, value:100000000000000000000000
277 0x0000d3c2, // precision:25, value:1000000000000000000000000
278 0x00084595, // precision:26, value:10000000000000000000000000
279 0x0052b7d2, // precision:27, value:100000000000000000000000000
280 0x033b2e3c, // precision:28, value:1000000000000000000000000000
281 0x204fce5e, // precision:29, value:10000000000000000000000000000
282 0x431e0fae, // precision:30, value:100000000000000000000000000000
283 0x9f2c9cd0, // precision:31, value:1000000000000000000000000000000
284 0x37be2022, // precision:32, value:10000000000000000000000000000000
285 0x2d6d415b, // precision:33, value:100000000000000000000000000000000
286 0xc6448d93, // precision:34, value:1000000000000000000000000000000000
287 0xbead87c0, // precision:35, value:10000000000000000000000000000000000
288 0x72c74d82, // precision:36, value:100000000000000000000000000000000000
289 0x7bc90715, // precision:37, value:1000000000000000000000000000000000000
290 0xd5da46d9, // precision:38, value:10000000000000000000000000000000000000
291 0x5a86c47a, // precision:38+1, value:99999999999999999999999999999999999999+1
294 static private readonly UInt32[] DecimalHelpersHiHi = {
295 0x00000000, // precision:2, value:10
296 0x00000000, // precision:3, value:100
297 0x00000000, // precision:4, value:1000
298 0x00000000, // precision:5, value:10000
299 0x00000000, // precision:6, value:100000
300 0x00000000, // precision:7, value:1000000
301 0x00000000, // precision:8, value:10000000
302 0x00000000, // precision:9, value:100000000
303 0x00000000, // precision:10, value:1000000000
304 0x00000000, // precision:11, value:10000000000
305 0x00000000, // precision:12, value:100000000000
306 0x00000000, // precision:13, value:1000000000000
307 0x00000000, // precision:14, value:10000000000000
308 0x00000000, // precision:15, value:100000000000000
309 0x00000000, // precision:16, value:1000000000000000
310 0x00000000, // precision:17, value:10000000000000000
311 0x00000000, // precision:18, value:100000000000000000
312 0x00000000, // precision:19, value:1000000000000000000
313 0x00000000, // precision:20, value:10000000000000000000
314 0x00000000, // precision:21, value:100000000000000000000
315 0x00000000, // precision:22, value:1000000000000000000000
316 0x00000000, // precision:23, value:10000000000000000000000
317 0x00000000, // precision:24, value:100000000000000000000000
318 0x00000000, // precision:25, value:1000000000000000000000000
319 0x00000000, // precision:26, value:10000000000000000000000000
320 0x00000000, // precision:27, value:100000000000000000000000000
321 0x00000000, // precision:28, value:1000000000000000000000000000
322 0x00000000, // precision:29, value:10000000000000000000000000000
323 0x00000001, // precision:30, value:100000000000000000000000000000
324 0x0000000c, // precision:31, value:1000000000000000000000000000000
325 0x0000007e, // precision:32, value:10000000000000000000000000000000
326 0x000004ee, // precision:33, value:100000000000000000000000000000000
327 0x0000314d, // precision:34, value:1000000000000000000000000000000000
328 0x0001ed09, // precision:35, value:10000000000000000000000000000000000
329 0x00134261, // precision:36, value:100000000000000000000000000000000000
330 0x00c097ce, // precision:37, value:1000000000000000000000000000000000000
331 0x0785ee10, // precision:38, value:10000000000000000000000000000000000000
332 0x4b3b4ca8, // precision:38+1, value:99999999999999999999999999999999999999+1
336 // note that the algorithm covers a range from -5 to +4 from the initial index
337 // at the end of the algorithm the tableindex will point to the greatest value that is
338 // less than the current value
339 // except (!) if the current value is less than 10 (precision=1). There is no value ins
340 // the table that is less than 10. In this case the algorithm terminates earlier.
342 // The startindex values have been chosen so that the highest possible index (startindex+5)
343 // does not point to a value that has bits in a higher word set
345 private const int HelperTableStartIndexLo = 5;
346 private const int HelperTableStartIndexMid = 15;
347 private const int HelperTableStartIndexHi = 24;
348 private const int HelperTableStartIndexHiHi = 33;
350 private byte CalculatePrecision() {
353 UInt32[] decimalHelpers;
357 tableIndex = HelperTableStartIndexHiHi;
358 decimalHelpers = DecimalHelpersHiHi;
359 decimalPart = m_data4;
361 else if (m_data3 != 0) {
362 tableIndex = HelperTableStartIndexHi;
363 decimalHelpers = DecimalHelpersHi;
364 decimalPart = m_data3;
366 else if (m_data2 != 0) {
367 tableIndex = HelperTableStartIndexMid;
368 decimalHelpers = DecimalHelpersMid;
369 decimalPart = m_data2;
372 tableIndex = HelperTableStartIndexLo;
373 decimalHelpers = DecimalHelpersLo;
374 decimalPart = m_data1;
378 // this code will move the index no more than -2 -2 -1 (-5) or +2 +1 +1 (+4)
379 // from the initial position
381 if (decimalPart < decimalHelpers[tableIndex]) {
383 if (decimalPart < decimalHelpers[tableIndex]) {
385 if (decimalPart < decimalHelpers[tableIndex]) {
398 if (decimalPart < decimalHelpers[tableIndex]) {
405 if (decimalPart >= decimalHelpers[tableIndex]) {
407 if (tableIndex == 37 && decimalPart >= decimalHelpers[tableIndex]) {
408 // This can happen only if the actual value is greater than 1E+38,
409 // in which case, tableIndex starts at 33 and ends at 37.
410 // Note that in this case, the actual value will be out of SqlDeicmal's range,
411 // and tableIndex is out of the array boudary. We'll throw later in ctors.
416 precision = (byte)(tableIndex + 1);
419 // tableIndex may still be off by one since we didn't look at the lower words
421 if (VerifyPrecision((byte)(precision-1))) {
425 Debug.Assert ((precision == MaxPrecision+1) || VerifyPrecision(precision), "Calcualted precision too low?");
426 Debug.Assert ((precision == 1) || !VerifyPrecision((byte)(precision-1)), "Calculated precision too high?");
428 // adjust the precision
429 // This might not be correct but is to our best knowledge
430 precision = Math.Max(precision, m_bScale);
432 byte bPrec = m_bPrec; // store current value
433 m_bPrec = MaxPrecision; // BActualPrec does not work if m_bPrec uninitialized!
434 byte bActualPrecision = BActualPrec();
435 m_bPrec=bPrec; // restore current value
437 Debug.Assert (precision==bActualPrecision,String.Format((IFormatProvider)null, "CalculatePrecision={0}, BActualPrec={1}. Results must be equal!", precision, bActualPrecision));
444 // returns true if the current value is less or equal than the max value of the
445 // supplied precision.
447 private bool VerifyPrecision (byte precision) {
448 Debug.Assert(precision>0,"Precision cannot be less than 1");
449 Debug.Assert(precision<=MaxPrecision, "Precision > MaxPrecision");
451 int tableIndex = checked((int)precision -1);
452 if (m_data4 < DecimalHelpersHiHi[tableIndex]) {
455 else if (m_data4 == DecimalHelpersHiHi[tableIndex]) {
456 if (m_data3 < DecimalHelpersHi[tableIndex]) {
459 else if (m_data3 == DecimalHelpersHi[tableIndex]) {
460 if (m_data2 < DecimalHelpersMid[tableIndex]) {
463 else if (m_data2 == DecimalHelpersMid[tableIndex]) {
464 if (m_data1 < DecimalHelpersLo[tableIndex]) {
477 private SqlDecimal(bool fNull) {
489 /// <para>[To be supplied.]</para>
491 public SqlDecimal(Decimal value) {
493 m_bStatus = x_bNotNull;
495 // note: using usafe code we could get the data directly out of the structure like that:
496 // UInt32 * pInt = (UInt32*) &value;
497 // UInt32 sgnscl = *pInt++;
499 // m_data3 = *pInt++; // high part
500 // m_data1 = *pInt++; // lo part
501 // m_data2 = *pInt++; // mid part
503 int[] bits = Decimal.GetBits(value);
505 UInt32 sgnscl = (UInt32)bits[3];
506 m_data1 = (UInt32)bits[0];
507 m_data2 = (UInt32)bits[1];
508 m_data3 = (UInt32)bits[2];
512 m_bStatus |= ((sgnscl & 0x80000000) == 0x80000000)? x_bNegative:(byte)0;
516 else if (m_data2 != 0)
521 // Get the scale info from Decimal
522 m_bScale = (byte)((int)(sgnscl & 0xff0000) >>16);
524 // initialize precision
525 m_bPrec = 0; // The this object cannot be used before all of its fields are assigned to
528 m_bPrec = CalculatePrecision();
529 // CalculatePrecision adjusts!
530 // if (m_bPrec < m_bScale)
531 // m_bPrec = m_bScale;
535 /// <para>[To be supplied.]</para>
537 public SqlDecimal(int value) {
539 m_bStatus = x_bNotNull;
541 uint uiValue = (uint) value;
545 m_bStatus |= x_bNegative;
546 // The negative of -2147483648 doesn't fit into int32, directly cast to int should work.
547 if (value != Int32.MinValue)
548 uiValue = (uint)(- value);
553 m_data2 = m_data3 = m_data4 = x_uiZero;
556 m_bPrec = BGetPrecUI4(m_data1);
561 /// <para>[To be supplied.]</para>
563 public SqlDecimal(long value) {
565 m_bStatus = x_bNotNull;
567 ulong dwl = (ulong)value;
571 m_bStatus |= x_bNegative;
572 // The negative of Int64.MinValue doesn't fit into int64, directly cast to ulong should work.
573 if (value != Int64.MinValue)
574 dwl = (ulong)(- value);
577 // Copy DWL into bottom 2 UI4s of numeric
579 m_data2 = (uint)(dwl >> 32);
580 m_data3 = m_data4 = 0;
582 // Trim any leading zero from the length
583 m_bLen = (byte)((m_data2 == 0) ? 1 : 2);
585 m_bPrec = BGetPrecUI8(dwl);
592 /// <para>[To be supplied.]</para>
594 public SqlDecimal(byte bPrecision, byte bScale, bool fPositive, int[] bits) {
595 CheckValidPrecScale(bPrecision, bScale);
597 throw new ArgumentNullException("bits");
598 else if (bits.Length != 4)
599 throw new ArgumentException(SQLResource.InvalidArraySizeMessage, "bits");
601 m_bPrec = bPrecision;
603 m_data1 = (uint)bits[0];
604 m_data2 = (uint)bits[1];
605 m_data3 = (uint)bits[2];
606 m_data4 = (uint)bits[3];
608 for (int i = 3; i >= 0; i --) {
610 m_bLen = (byte)(i + 1);
616 m_bStatus = x_bNotNull;
620 m_bStatus |= x_bNegative;
623 // If result is -0, adjust sign to positive.
627 if (bPrecision < CalculatePrecision())
628 throw new OverflowException(SQLResource.ArithOverflowMessage);
632 /// <para>[To be supplied.]</para>
634 public SqlDecimal(byte bPrecision, byte bScale, bool fPositive, int data1, int data2, int data3, int data4) {
635 CheckValidPrecScale(bPrecision, bScale);
636 m_bPrec = bPrecision;
639 m_data1 = (uint)data1;
640 m_data2 = (uint)data2;
641 m_data3 = (uint)data3;
642 m_data4 = (uint)data4;
657 m_bStatus = x_bNotNull;
661 m_bStatus |= x_bNegative;
664 // If result is -0, adjust sign to positive.
668 if (bPrecision < CalculatePrecision())
669 throw new OverflowException(SQLResource.ArithOverflowMessage);
673 /// <para>[To be supplied.]</para>
675 public SqlDecimal(double dVal) : this(false) {
677 m_bStatus = x_bNotNull;
679 // Split double to sign, integer, and fractional parts
682 m_bStatus |= x_bNegative;
685 // If it will not fit into numeric(NUMERIC_MAX_PRECISION,0), overflow.
686 if (dVal >= DMAX_NUME)
687 throw new OverflowException(SQLResource.ArithOverflowMessage);
689 double dInt = Math.Floor(dVal);
690 double dFrac = dVal - dInt;
692 m_bPrec = NUMERIC_MAX_PRECISION;
695 dVal = Math.Floor (dInt / DUINT_BASE);
696 m_data1 = (uint)(dInt - dVal * DUINT_BASE);
700 dVal = Math.Floor (dInt / DUINT_BASE);
701 m_data2 = (uint)(dInt - dVal * DUINT_BASE);
706 dVal = Math.Floor (dInt / DUINT_BASE);
707 m_data3 = (uint)(dInt - dVal * DUINT_BASE);
712 dVal = Math.Floor (dInt / DUINT_BASE);
713 m_data4 = (uint) (dInt - dVal * DUINT_BASE);
721 uint ulLen, ulLenDelta;
724 // Get size of the integer part
725 ulLen = FZero() ? 0 : (uint)CalculatePrecision();
726 SQLDebug.Check(ulLen <= NUMERIC_MAX_PRECISION, "ulLen <= NUMERIC_MAX_PRECISION", "");
728 // If we got more than 17 decimal digits, zero lower ones.
729 if (ulLen > DBL_DIG) {
730 // Divide number by 10 while there are more then 17 digits
731 uint ulWrk = ulLen - DBL_DIG;
733 ulTemp = DivByULong (10);
737 ulWrk = ulLen - DBL_DIG;
739 // Round, if necessary. # of digits can change. Cannot be overflow.
742 ulLen = CalculatePrecision() + ulWrk;
753 m_bScale = (byte)(ulLen < DBL_DIG ? DBL_DIG - ulLen : 0);
754 m_bPrec = (byte)(ulLen + m_bScale);
756 // Add meaningful fractional part - max 9 digits per iteration
760 ulLenDelta = (ulLen >= 9) ? 9 : ulLen;
762 dFrac *= (double) x_rgulShiftBase[(int)ulLenDelta-1];
764 MultByULong (x_rgulShiftBase[(int)ulLenDelta-1]);
765 AddULong ((uint) dFrac);
766 dFrac -= Math.Floor (dFrac);
771 // Round, if necessary
782 private SqlDecimal(uint[] rglData, byte bLen, byte bPrec, byte bScale, bool fPositive) {
783 CheckValidPrecScale(bPrec, bScale);
784 SQLDebug.Check(rglData.Length >= 4);
789 m_data1 = rglData[0];
790 m_data2 = rglData[1];
791 m_data3 = rglData[2];
792 m_data4 = rglData[3];
795 m_bStatus = x_bNotNull;
799 m_bStatus |= x_bNegative;
802 // If result is -0, adjust sign to positive.
810 /// <para>[To be supplied.]</para>
813 get { return(m_bStatus & x_bNullMask) == x_bIsNull;}
817 /// <para>[To be supplied.]</para>
819 public Decimal Value {
820 get { return ToDecimal();}
824 /// <para>[To be supplied.]</para>
826 public bool IsPositive {
829 throw new SqlNullValueException();
830 return(m_bStatus & x_bSignMask) == x_bPositive;
834 private void SetPositive() {
835 SQLDebug.Check(!IsNull);
836 m_bStatus = (byte)(m_bStatus & x_bReverseSignMask);
839 private void SetSignBit(bool fPositive) {
840 SQLDebug.Check(!IsNull);
841 m_bStatus = (byte)(fPositive ? (m_bStatus & x_bReverseSignMask) : (m_bStatus | x_bNegative));
845 /// <para>[To be supplied.]</para>
847 public byte Precision {
850 throw new SqlNullValueException();
856 /// <para>[To be supplied.]</para>
861 throw new SqlNullValueException();
867 /// <para>[To be supplied.]</para>
872 throw new SqlNullValueException();
873 return new int[4] { (int)m_data1, (int)m_data2, (int)m_data3, (int)m_data4};
878 /// <para>[To be supplied.]</para>
880 public byte[] BinData {
883 throw new SqlNullValueException();
885 int data1 = (int)m_data1;
886 int data2 = (int)m_data2;
887 int data3 = (int)m_data3;
888 int data4 = (int)m_data4;
889 byte[] rgBinData = new byte[16];
890 rgBinData[0] = (byte)(data1 & 0xff);
892 rgBinData[1] = (byte)(data1 & 0xff);
894 rgBinData[2] = (byte)(data1 & 0xff);
896 rgBinData[3] = (byte)(data1 & 0xff);
897 rgBinData[4] = (byte)(data2 & 0xff);
899 rgBinData[5] = (byte)(data2 & 0xff);
901 rgBinData[6] = (byte)(data2 & 0xff);
903 rgBinData[7] = (byte)(data2 & 0xff);
904 rgBinData[8] = (byte)(data3 & 0xff);
906 rgBinData[9] = (byte)(data3 & 0xff);
908 rgBinData[10] = (byte)(data3 & 0xff);
910 rgBinData[11] = (byte)(data3 & 0xff);
911 rgBinData[12] = (byte)(data4 & 0xff);
913 rgBinData[13] = (byte)(data4 & 0xff);
915 rgBinData[14] = (byte)(data4 & 0xff);
917 rgBinData[15] = (byte)(data4 & 0xff);
924 /// <para>[To be supplied.]</para>
926 public override String ToString() {
928 return SQLResource.NullString;
931 // Make local copy of data to avoid modifying input.
932 uint[] rgulNumeric = new uint[4] { m_data1, m_data2, m_data3, m_data4};
934 char[] pszTmp = new char[NUMERIC_MAX_PRECISION + 1]; //Local Character buffer to hold
935 //the decimal digits, from the
936 //lowest significant to highest significant
938 int iDigits = 0;//Number of significant digits
939 uint ulRem; //Remainder of a division by x_ulBase10, i.e.,least significant digit
941 // Build the final numeric string by inserting the sign, reversing
942 // the order and inserting the decimal number at the correct position
944 //Retrieve each digit from the lowest significant digit
945 while (culLen > 1 || rgulNumeric[0] != 0) {
946 MpDiv1 (rgulNumeric, ref culLen, x_ulBase10, out ulRem);
947 //modulo x_ulBase10 is the lowest significant digit
948 pszTmp[iDigits++] = ChFromDigit(ulRem);
951 // if scale of the number has not been
952 // reached pad remaining number with zeros.
953 while (iDigits <= m_bScale) {
954 pszTmp[iDigits++] = ChFromDigit(0);
962 // Increment the result length if scale > 0 (need to add '.')
968 szResult = new char[uiResultLen + iDigits];
971 // Increment the result length if negative (need to add '-')
972 szResult = new char[uiResultLen + iDigits + 1];
973 szResult[iCurChar ++] = '-';
976 while (iDigits > 0) {
977 if (iDigits-- == m_bScale)
978 szResult[iCurChar ++] = '.';
980 szResult[iCurChar ++] = pszTmp[iDigits];
985 return new String(szResult);
989 /// <para>[To be supplied.]</para>
991 public static SqlDecimal Parse(String s) {
993 throw new ArgumentNullException("s");
995 if (s == SQLResource.NullString)
996 return SqlDecimal.Null;
998 SqlDecimal snResult = SqlDecimal.Null;
1000 char[] rgwchStr = s.ToCharArray();
1001 int cwchStr = rgwchStr.Length;
1003 int iData; //index to string
1004 char usChar; //current value in string
1005 int lDecPnt = -1; //position of decimal point in string
1008 //Must initialize precision and scale to valid values
1009 snResult.m_bPrec = 1;
1010 snResult.m_bScale = 0;
1012 //Must initialize *this to zero
1013 snResult.SetToZero ();
1015 // Trim trailing blanks.
1016 while (cwchStr != 0 && rgwchStr[cwchStr-1] == ' ')
1019 // If string contains only spaces, stop
1021 throw new FormatException(SQLResource.FormatMessage);
1023 // Trim leading blanks.
1024 while (rgwchStr[iCurChar] == ' ') {
1029 // Get sign for numeric value.
1030 if (rgwchStr[iCurChar] == '-') {
1031 snResult.SetSignBit(false);
1036 snResult.SetSignBit(true);
1037 if (rgwchStr[iCurChar] == '+') {
1043 // Hack: Check for "0.". If so, replace by ".0".
1044 while ((cwchStr > 2) && (rgwchStr[iCurChar] == '0')) {
1048 if (2 == cwchStr && '0' == rgwchStr[iCurChar] && '.' == rgwchStr[iCurChar + 1]) {
1049 rgwchStr[iCurChar] = '.';
1050 rgwchStr[iCurChar + 1] = '0';
1054 if (cwchStr == 0 || cwchStr > NUMERIC_MAX_PRECISION + 1)
1055 throw new FormatException(SQLResource.FormatMessage);
1057 // Trim leading zeros. (There shouldn't be any except for floats
1058 // less than 1. e.g. 0.01)
1059 while ((cwchStr > 1) && (rgwchStr[iCurChar] == '0')) {
1064 // Convert string to numeric value by looping through input string.
1065 for(iData=0; iData < cwchStr; iData++)
1067 usChar = rgwchStr[iCurChar];
1070 if (usChar >= '0' && usChar <= '9')
1072 else if (usChar == '.' && lDecPnt < 0) {
1077 throw new FormatException(SQLResource.FormatMessage);
1079 snResult.MultByULong(x_ulBase10);
1080 snResult.AddULong(usChar);
1083 // Save precision and scale.
1085 snResult.m_bPrec = (byte)iData;
1086 snResult.m_bScale = 0;
1089 snResult.m_bPrec = (byte)(iData - 1);
1090 snResult.m_bScale = (byte) (snResult.m_bPrec - lDecPnt);
1093 //Check for overflow condition
1094 if (snResult.m_bPrec > NUMERIC_MAX_PRECISION)
1095 throw new FormatException(SQLResource.FormatMessage);
1097 // Check for invalid precision for numeric value.
1098 // e.g., when string is ".", precision will be 0
1099 if (snResult.m_bPrec == 0)
1100 throw new FormatException(SQLResource.FormatMessage);
1102 // If result is -0, adjust sign to positive.
1103 if (snResult.FZero())
1104 snResult.SetPositive();
1106 snResult.AssertValid();
1112 /// <para>[To be supplied.]</para>
1114 public double ToDouble() {
1116 throw new SqlNullValueException();
1120 dRet = (double)m_data4;
1121 dRet = dRet * x_lInt32Base + m_data3;
1122 dRet = dRet * x_lInt32Base + m_data2;
1123 dRet = dRet * x_lInt32Base + m_data1;
1125 dRet /= System.Math.Pow(10.0, m_bScale);
1127 return IsPositive ? dRet : - dRet;
1130 private Decimal ToDecimal() {
1132 throw new SqlNullValueException();
1134 if ((int)m_data4 != 0 || m_bScale > 28)
1135 throw new OverflowException(SQLResource.ConversionOverflowMessage);
1137 return new Decimal((int)m_data1, (int)m_data2, (int)m_data3, !IsPositive, m_bScale);
1140 // Implicit conversion from Decimal to SqlDecimal
1142 /// <para>[To be supplied.]</para>
1144 public static implicit operator SqlDecimal(Decimal x) {
1145 return new SqlDecimal(x);
1148 // Explicit conversion from Double to SqlDecimal
1149 public static explicit operator SqlDecimal(double x) {
1150 return new SqlDecimal(x);
1153 // Implicit conversion from long to SqlDecimal
1154 public static implicit operator SqlDecimal(long x) {
1155 return new SqlDecimal(new Decimal(x));
1158 // Explicit conversion from SqlDecimal to Decimal. Throw exception if x is Null.
1160 /// <para>[To be supplied.]</para>
1162 public static explicit operator Decimal(SqlDecimal x) {
1169 /// <para>[To be supplied.]</para>
1171 public static SqlDecimal operator -(SqlDecimal x) {
1179 s.SetSignBit(!s.IsPositive);
1187 // Arithmetic operators
1189 /// <para>[To be supplied.]</para>
1191 public static SqlDecimal operator +(SqlDecimal x, SqlDecimal y) {
1192 if (x.IsNull || y.IsNull)
1195 ulong dwlAccum; //accumulated sum
1196 bool fMySignPos; //sign of x was positive at start
1197 bool fOpSignPos; // sign of y positive at start
1198 bool fResSignPos = true; //sign of result should be positive
1199 int MyScale; //scale of x
1200 int OpScale; //scale of y
1201 int ResScale; //scale of result
1202 int ResPrec; //precision of result
1203 int ResInteger; //number of digits for the integer part of result
1204 int culOp1; //# of UI4s in x
1205 int culOp2; //# of UI4s in y
1206 int iulData; //which UI4 we are operating on in x, y
1207 byte bLen; // length for the result
1213 fMySignPos = x.IsPositive;
1214 fOpSignPos = y.IsPositive;
1216 //result scale = max(s1,s2)
1217 //result precison = max(s1,s2) + max(p1-s1,p2-s2)
1218 MyScale = x.m_bScale;
1219 OpScale = y.m_bScale;
1221 // Calculate the integer part of the result.
1222 ResInteger = Math.Max((int)x.m_bPrec - MyScale, (int)y.m_bPrec - OpScale);
1223 SQLDebug.Check (ResInteger <= MaxPrecision);
1225 // Calculate the scale of the result.
1226 ResScale = Math.Max(MyScale, OpScale);
1227 SQLDebug.Check (ResScale <= MaxScale);
1229 // Calculate the precision of the result.
1230 // Add 1 for final carry.
1231 ResPrec = ResInteger + ResScale + 1;
1232 ResPrec = Math.Min(MaxPrecision, ResPrec);
1234 // If precision adjusted, scale is reduced to keep the integer part untruncated.
1235 // But discard the extra carry, only keep the interger part as ResInteger, not ResInteger + 1.
1236 SQLDebug.Check(ResPrec - ResInteger >= 0);
1237 if (ResPrec - ResInteger < ResScale)
1238 ResScale = ResPrec - ResInteger;
1240 // Adjust both operands to be the same scale as ResScale.
1241 if (MyScale != ResScale)
1242 x.AdjustScale(ResScale - MyScale, true);
1244 if (OpScale != ResScale)
1245 y.AdjustScale(ResScale - OpScale, true);
1247 // When sign of first operand is negative
1248 // negate all operands including result.
1250 fMySignPos = !fMySignPos;
1251 fOpSignPos = !fOpSignPos;
1252 fResSignPos = !fResSignPos;
1255 // Initialize operand lengths and pointer.
1259 uint[] rglData1 = new uint[4] {x.m_data1, x.m_data2, x.m_data3, x.m_data4};
1260 uint[] rglData2 = new uint[4] {y.m_data1, y.m_data2, y.m_data3, y.m_data4};
1267 // Loop through UI4s adding operands and putting result in *this
1268 // of the operands and put result in *this
1269 for (iulData = 0; iulData < culOp1 || iulData < culOp2; iulData++) {
1270 // None of these DWORDLONG additions can overflow, as dwlAccum comes in < x_lInt32Base
1271 if (iulData < culOp1)
1272 dwlAccum += rglData1[iulData];
1273 if (iulData < culOp2)
1274 dwlAccum += rglData2[iulData];
1276 rglData1[iulData] = (uint)dwlAccum; // equiv to mod x_lInt32Base
1277 dwlAccum >>= 32; // equiv to div x_lInt32Base
1281 if (dwlAccum != 0) {
1282 SQLDebug.Check(dwlAccum < x_ulInt32Base);
1285 if (iulData == x_cNumeMax)
1286 throw new OverflowException(SQLResource.ArithOverflowMessage);
1288 // Or extended length
1289 rglData1[iulData] = (uint)dwlAccum;
1293 // Set result length
1294 bLen = (byte) iulData;
1297 int iulLastNonZero = 0; // The last nonzero UI
1299 // When second operand is negative, switch operands
1300 // if operand2 is greater than operand1
1301 if (x.LAbsCmp (y) < 0) {
1302 fResSignPos = !fResSignPos;
1303 uint[] rguiTemp = rglData2;
1304 rglData2 = rglData1;
1305 rglData1 = rguiTemp;
1310 dwlAccum = x_ulInt32Base;
1311 for (iulData = 0; iulData < culOp1 || iulData < culOp2; iulData++) {
1312 if (iulData < culOp1)
1313 dwlAccum += rglData1[iulData];
1314 if (iulData < culOp2)
1315 dwlAccum -= rglData2[iulData];
1317 rglData1[iulData] = (uint)dwlAccum; // equiv to mod BaseUI4
1318 if (rglData1[iulData] != 0)
1319 iulLastNonZero = iulData;
1320 dwlAccum >>= 32; // equiv to /= BaseUI4
1321 dwlAccum += x_ulInt32BaseForMod; // equiv to BaseUI4 - 1
1323 // Set length based on highest non-zero ULONG
1324 bLen = (byte) (iulLastNonZero + 1);
1327 SqlDecimal ret = new SqlDecimal(rglData1, bLen, (byte)ResPrec, (byte)ResScale, fResSignPos);
1329 if (ret.FGt10_38() || ret.CalculatePrecision () > NUMERIC_MAX_PRECISION)
1330 throw new OverflowException(SQLResource.ArithOverflowMessage);
1341 /// <para>[To be supplied.]</para>
1343 public static SqlDecimal operator -(SqlDecimal x, SqlDecimal y) {
1349 // Multiply two numerics.
1352 // x - IN Multiplier
1353 // y - IN Multiplicand
1355 // Result scale and precision(same as in SQL Server Manual and Hydra):
1357 // precison = s1 + s2 + (p1 - s1) + (p2 - s2) + 1
1360 // If scale is greater than NUMERIC_MAX_PRECISION it is set to
1361 // NUMERIC_MAX_PRECISION. If precision is greater than NUMERIC_MAX_PRECISION
1362 // it is set to NUMERIC_MAX_PRECISION, then scale is reduced to keep the
1363 // integer part untruncated but keeping a minimum value of x_cNumeDivScaleMin.
1364 // For example, if using the above formula, the resulting precision is 46 and
1365 // scale is 10, the precision will be reduced to 38. To keep the integral part
1366 // untruncated the scale needs be reduced to 2, but since x_cNumeDivScaleMin
1367 // is set to 6 currently, resulting scale will be 6.
1368 // O_OVERFLOW is returned only if the actual precision is greater than
1369 // NUMERIC_MAX_PRECISION or the actual length is greater than x_cbNumeBuf.
1372 // Starting from the lowest significant UI4, for each UI4 of the multiplier
1373 // iterate through the UI4s of the multiplicand starting from
1374 // the least significant UI4s, multiply the multiplier UI4 with
1375 // multiplicand UI4, update the result buffer with the product modulo
1376 // x_dwlBaseUI4 at the same index as the multiplicand, and carry the quotient to
1377 // add to the next multiplicand UI4. Until the end of the multiplier data
1378 // array is reached.
1381 /// <para>[To be supplied.]</para>
1383 public static SqlDecimal operator *(SqlDecimal x, SqlDecimal y) {
1387 if (x.IsNull || y.IsNull)
1391 // I) Figure result scale,prec
1392 // II) Perform mult.
1393 // III) Adjust product to result scale,prec
1395 // Local variables for actual multiplication
1396 int iulPlier; //index of UI4 in the Multiplier
1397 uint ulPlier; //current mutiplier UI4
1398 ulong dwlAccum; //accumulated sum
1399 ulong dwlNextAccum; //overflow of accumulated sum
1400 int culCand = y.m_bLen; //length of multiplicand in UI4s
1402 //Local variables to track scale,precision
1403 int ActualScale; // Scale after mult done
1404 int ResScale; // Final scale we will force result to
1405 int ResPrec; // Final precision we will force result to
1406 int ResInteger; // # of digits in integer part of result (prec-scale)
1407 int lScaleAdjust; //How much result scale will be adjusted
1408 bool fResPositive; // Result sign
1413 //I) Figure result prec,scale
1414 ActualScale = x.m_bScale + y.m_bScale;
1415 ResScale = ActualScale;
1416 ResInteger = (x.m_bPrec - x.m_bScale) + (y.m_bPrec - y.m_bScale) + 1;
1418 //result precison = s1 + s2 + (p1 - s1) + (p2 - s2) + 1
1419 ResPrec = ResScale + ResInteger;
1421 // Downward adjust res prec,scale if either larger than NUMERIC_MAX_PRECISION
1422 if (ResPrec > NUMERIC_MAX_PRECISION)
1423 ResPrec = NUMERIC_MAX_PRECISION;
1424 if (ResScale > NUMERIC_MAX_PRECISION)
1425 ResScale = NUMERIC_MAX_PRECISION;
1428 // It is possible when two large numbers are being multiplied the scale
1429 // can be reduced to 0 to keep data untruncated; the fix here is to
1430 // preserve a minimum scale of 6.
1432 // If overflow, reduce the scale to avoid truncation of data
1433 ResScale = Math.Min((ResPrec - ResInteger),ResScale);
1434 // But keep a minimum scale of NUMERIC_MIN_DVSCALE
1435 ResScale = Math.Max(ResScale, Math.Min(ActualScale,x_cNumeDivScaleMin));
1437 lScaleAdjust = ResScale - ActualScale;
1439 fResPositive = (x.IsPositive == y.IsPositive);//positive if both signs same.
1441 // II) Perform multiplication
1443 uint[] rglData1 = new uint[4] {x.m_data1, x.m_data2, x.m_data3, x.m_data4};
1444 uint[] rglData2 = new uint[4] {y.m_data1, y.m_data2, y.m_data3, y.m_data4};
1446 //Local buffer to hold the result of multiplication.
1447 //Longer than CReNumeBuf because full precision of multiplication is carried out
1448 const int x_culNumeMultRes = 9; // Maximum # UI4s in result buffer in multiplication
1449 uint[] rgulRes = new uint[x_culNumeMultRes]; //new [] are already initialized to zero
1450 int culRes; // # of UI4s in result
1453 //Iterate over the bytes of multiplier
1454 for (iulPlier = 0; iulPlier < x.m_bLen; iulPlier++) {
1455 ulPlier = rglData1[iulPlier];
1458 //Multiply each UI4 of multiCand by ulPliear and accumulate into result buffer
1460 // Start on correct place in result
1463 for (int iulCand = 0; iulCand < culCand; iulCand++) {
1464 // dwlAccum = dwlAccum + rgulRes[idRes] + ulPlier*rglData2[iulCand]
1465 // use dwlNextAccum to detect overflow of DWORDLONG
1466 dwlNextAccum = dwlAccum + rgulRes[idRes];
1467 ulong ulTemp = (ulong)rglData2[iulCand];
1468 dwlAccum = (ulong)ulPlier * ulTemp;
1469 dwlAccum += dwlNextAccum;
1470 if (dwlAccum < dwlNextAccum) // indicates dwl addition overflowed
1471 dwlNextAccum = x_ulInt32Base; // = maxUI64/x_dwlBaseUI4
1475 // Update result and accum
1476 rgulRes[idRes ++] = (uint)(dwlAccum);// & x_ulInt32BaseForMod); // equiv to mod x_lInt32Base
1477 dwlAccum = (dwlAccum >> 32) + dwlNextAccum; // equiv to div BaseUI4 + dwlNAccum
1479 // dwlNextAccum can't overflow next iteration
1480 SQLDebug.Check(dwlAccum < x_ulInt32Base*2);
1483 SQLDebug.Check(dwlAccum < x_ulInt32Base); // can never final accum > 1 more UI4
1485 rgulRes[idRes ++] = (uint)dwlAccum;
1487 // Skip leading 0s (may exist if we are multiplying by 0)
1488 for (;(rgulRes[idRes] == 0) && (idRes > 0); idRes--)
1490 // Calculate actual result length
1493 // III) Adjust precision,scale to result prec,scale
1494 if (lScaleAdjust != 0) {
1495 // If need to decrease scale
1496 if (lScaleAdjust < 0) {
1497 SQLDebug.Check(NUMERIC_MAX_PRECISION == ResPrec);
1499 // have to adjust - might yet end up fitting.
1500 // Cannot call AdjustScale - number cannot fit in a numeric, so
1501 // have to duplicate code here
1503 uint ulRem; //Remainder when downshifting
1504 uint ulShiftBase; //What to multiply by to effect scale adjust
1507 if (lScaleAdjust <= -9) {
1508 ulShiftBase = x_rgulShiftBase[8];
1512 ulShiftBase = x_rgulShiftBase[-lScaleAdjust - 1];
1515 MpDiv1 (rgulRes, ref culRes, ulShiftBase, out ulRem);
1517 while (lScaleAdjust != 0);
1519 // Still do not fit?
1520 if (culRes > x_cNumeMax)
1521 throw new OverflowException(SQLResource.ArithOverflowMessage);
1523 for (idRes = culRes; idRes < x_cNumeMax; idRes ++)
1525 ret = new SqlDecimal(rgulRes, (byte)culRes, (byte)ResPrec, (byte)ResScale, fResPositive);
1527 // Is it greater than 10**38?
1529 throw new OverflowException(SQLResource.ArithOverflowMessage);
1533 // If remainder is 5 or above, increment/decrement by 1.
1534 if (ulRem >= ulShiftBase/2)
1536 // After adjusting, if the result is 0 and remainder is less than 5,
1537 // set the sign to be positive
1544 // Otherwise call AdjustScale
1545 if (culRes > x_cNumeMax) // Do not fit now, so will not fit after asjustement
1546 throw new OverflowException(SQLResource.ArithOverflowMessage);
1547 // NOTE: Have not check for value in the range (10**38..2**128),
1548 // as we'll call AdjustScale with positive argument, and it'll
1549 // return "normal" overflow
1551 for (idRes = culRes; idRes < x_cNumeMax; idRes ++)
1553 ret = new SqlDecimal(rgulRes, (byte)culRes, (byte)ResPrec, (byte)ActualScale, fResPositive);
1560 ret.AdjustScale(lScaleAdjust, true);
1565 if (culRes > x_cNumeMax)
1566 throw new OverflowException(SQLResource.ArithOverflowMessage);
1568 for (idRes = culRes; idRes < x_cNumeMax; idRes ++)
1570 ret = new SqlDecimal(rgulRes, (byte)culRes, (byte)ResPrec, (byte)ResScale, fResPositive);
1572 // Is it greater than 10**38?
1573 if (ret.FGt10_38 ())
1574 throw new OverflowException(SQLResource.ArithOverflowMessage);
1585 //-----------------------------------------------------------
1587 // Divide numeric by numeric.
1588 // The Quotient will be returned in *this
1590 //Result scale&precision:
1591 // NOTE: same as in Hydra but different from SQL Server Manual,
1592 // where scale = max(s1+p2-s2+1,x_cNumeDivScaleMin)):
1593 // scale = max(s1 + p2 + 1, x_cNumeDivScaleMin);
1594 // precision = max(s1 + p2 + 1, x_cNumeDivScaleMin) + p1 + p2 + 1;
1597 // If scale is greater than NUMERIC_MAX_PRECISION it is set to
1598 // NUMERIC_MAX_PRECISION. If precision is greater than NUMERIC_MAX_PRECISION
1599 // it's set to NUMERIC_MAX_PRECISION, then scale is reduced to keep the
1600 // integer part untruncated but keeping a minimum value of x_cNumeDivScaleMin.
1601 // For example, if using the above formula, the resulting precision is 46 and
1602 // scale is 10, the precision will be reduced to 38, to keep the integral part
1603 // untruncated the scale needs be recuded to 2, but since x_cNumeDivScaleMin
1604 // is set to 6 currently, resulting scale will be 6.
1605 // OverflowException is throwed only if the actual precision is greater than
1606 // NUMERIC_MAX_PRECISION or actual length is greater than x_cbNumeBuf
1609 // Call general purpose arbitrary precision division routine with scale = 0.
1610 // Scale,prec adjusted later.
1613 /// <para>[To be supplied.]</para>
1615 public static SqlDecimal operator /(SqlDecimal x, SqlDecimal y) {
1616 if (x.IsNull || y.IsNull)
1622 // Variables for figuring prec,scale
1623 int bScaleD; // Input Scale of dividend (output scale of remainder)
1624 int bPrecD; // Input Prec of dividend (output prec of remainder)
1625 int ResScale; // Final scale we will force quotient to
1626 int ResPrec; // Final precision we will force quotient to
1627 int ResInteger; // # of digits in integer part of result (prec-scale)
1628 int MinScale; // Temp to help compute ResScale
1629 int lScaleAdjust; // How much result scale will be adjusted
1630 bool fResSignPos; // sign of result
1633 // 1) Figure result prec,scale; adjust scale of dividend
1634 // 2) Compute result remainder/quotient in 0 scale numbers
1635 // 3) Set result prec,scale and adjust as necessary
1637 // 0) Check for Div by 0
1639 throw new DivideByZeroException(SQLResource.DivideByZeroMessage);
1641 // 1) Figure out result prec,scale,sign..
1642 fResSignPos = (x.IsPositive == y.IsPositive);//sign of result
1644 //scale = max(s1 + p2 + 1, x_cNumeDivScaleMin);
1645 //precision = max(s1 + p2 + 1, x_cNumeDivScaleMin) + p1 + p2 + 1;
1646 //For backward compatibility, use exactly the same scheme as in Hydra
1647 bScaleD = x.m_bScale;
1649 ResScale = Math.Max(x.m_bScale + y.m_bPrec + 1, x_cNumeDivScaleMin);
1650 ResInteger = x.m_bPrec - x.m_bScale + y.m_bScale;
1651 ResPrec = ResScale + x.m_bPrec + y.m_bPrec + 1;
1652 MinScale = Math.Min(ResScale, x_cNumeDivScaleMin);
1654 ResInteger = Math.Min(ResInteger, NUMERIC_MAX_PRECISION);
1655 ResPrec = ResInteger + ResScale;
1657 if (ResPrec > NUMERIC_MAX_PRECISION)
1658 ResPrec = NUMERIC_MAX_PRECISION;
1660 // If overflow, reduce the scale to avoid truncation of data
1661 ResScale = Math.Min((ResPrec - ResInteger), ResScale);
1662 ResScale = Math.Max(ResScale, MinScale);
1664 //Adjust the scale of the dividend
1665 lScaleAdjust = ResScale - (int)x.m_bScale + (int)y.m_bScale;
1666 x.AdjustScale(lScaleAdjust, true);
1668 // Step2: Actual Computation
1670 uint[] rgulData1 = new uint[4] {x.m_data1, x.m_data2, x.m_data3, x.m_data4};
1671 uint[] rgulData2 = new uint[4] {y.m_data1, y.m_data2, y.m_data3, y.m_data4};
1673 // Buffers for arbitrary precision divide
1674 uint[] rgulR = new uint[x_cNumeMax + 1];
1675 uint[] rgulQ = new uint[x_cNumeMax];
1676 // # of ULONGs in result
1679 // Divide mantissas. V is not zero - already checked.
1680 // Cannot overflow, as Q <= U, R <= V. (and both are positive)
1681 MpDiv(rgulData1, x.m_bLen, rgulData2, y.m_bLen, rgulQ, out culQ, rgulR, out culR);
1683 // Construct the result from Q
1684 ZeroToMaxLen (rgulQ, culQ);
1685 SqlDecimal ret = new SqlDecimal(rgulQ, (byte)culQ, (byte)ResPrec, (byte)ResScale, fResSignPos);
1697 // Implicit conversions
1699 // Implicit conversion from SqlBoolean to SqlDecimal
1701 /// <para>[To be supplied.]</para>
1703 public static explicit operator SqlDecimal(SqlBoolean x) {
1704 return x.IsNull ? Null : new SqlDecimal((int)x.ByteValue);
1707 // Implicit conversion from SqlByte to SqlDecimal
1709 /// <para>[To be supplied.]</para>
1711 public static implicit operator SqlDecimal(SqlByte x) {
1712 return x.IsNull ? Null : new SqlDecimal((int)(x.Value));
1715 // Implicit conversion from SqlInt16 to SqlDecimal
1717 /// <para>[To be supplied.]</para>
1719 public static implicit operator SqlDecimal(SqlInt16 x) {
1720 return x.IsNull ? Null : new SqlDecimal((int)(x.Value));
1723 // Implicit conversion from SqlInt32 to SqlDecimal
1725 /// <para>[To be supplied.]</para>
1727 public static implicit operator SqlDecimal(SqlInt32 x) {
1728 return x.IsNull ? Null : new SqlDecimal(x.Value);
1731 // Implicit conversion from SqlInt64 to SqlDecimal
1733 /// <para>[To be supplied.]</para>
1735 public static implicit operator SqlDecimal(SqlInt64 x) {
1736 return x.IsNull ? Null : new SqlDecimal(x.Value);
1739 // Implicit conversion from SqlMoney to SqlDecimal
1741 /// <para>[To be supplied.]</para>
1743 public static implicit operator SqlDecimal(SqlMoney x) {
1744 return x.IsNull ? Null : new SqlDecimal(x.ToDecimal());
1748 // Explicit conversions
1750 // Explicit conversion from SqlSingle to SqlDecimal
1752 /// <para>[To be supplied.]</para>
1754 public static explicit operator SqlDecimal(SqlSingle x) {
1755 return x.IsNull ? SqlDecimal.Null : new SqlDecimal((double)(x.Value));
1758 // Explicit conversion from SqlDouble to SqlDecimal
1760 /// <para>[To be supplied.]</para>
1762 public static explicit operator SqlDecimal(SqlDouble x) {
1763 return x.IsNull ? SqlDecimal.Null : new SqlDecimal(x.Value);
1766 // Explicit conversion from SqlString to SqlDecimal
1767 // Throws FormatException or OverflowException if necessary.
1769 /// <para>[To be supplied.]</para>
1771 public static explicit operator SqlDecimal(SqlString x) {
1772 return x.IsNull ? Null : SqlDecimal.Parse(x.Value);
1777 //----------------------------------------------------------------------
1778 // Is this RE numeric valid?
1779 [System.Diagnostics.Conditional("DEBUG")]
1780 private void AssertValid() {
1784 // Scale,Prec in range
1785 SQLDebug.Check(m_bScale <= NUMERIC_MAX_PRECISION, "m_bScale <= NUMERIC_MAX_PRECISION", "In AssertValid");
1786 SQLDebug.Check(m_bScale <= m_bPrec, "m_bScale <= m_bPrec", "In AssertValid");
1787 SQLDebug.Check(m_bScale >= 0, "m_bScale >= 0", "In AssertValid");
1788 SQLDebug.Check(m_bPrec > 0, "m_bPrec > 0", "In AssertValid");
1790 SQLDebug.Check(CLenFromPrec(m_bPrec) >= m_bLen, "CLenFromPrec(m_bPrec) >= m_bLen", "In AssertValid");
1791 SQLDebug.Check(m_bLen <= x_cNumeMax, "m_bLen <= x_cNumeMax", "In AssertValid");
1793 uint[] rglData = new uint[4] {m_data1, m_data2, m_data3, m_data4};
1795 // highest UI4 is non-0 unless value "zero"
1796 if (rglData[m_bLen-1] == 0) {
1797 SQLDebug.Check(m_bLen == 1, "m_bLen == 1", "In AssertValid");
1800 // All UI4s from length to end are 0
1801 for (int iulData = m_bLen; iulData < x_cNumeMax; iulData++)
1802 SQLDebug.Check(rglData[iulData] == 0, "rglData[iulData] == 0", "In AssertValid");
1805 // print the data members
1806 [System.Diagnostics.Conditional("DEBUG")]
1807 private void Print() {
1809 Debug.WriteLine("Numeric: Null");
1812 Debug.WriteLine("Numeric: data - " + m_data4.ToString() + ", " + m_data3.ToString() + ", " +
1813 m_data2.ToString() + ", " + m_data1.ToString());
1814 Debug.WriteLine("\tlen = " + m_bLen.ToString() + ", Prec = " + m_bPrec.ToString() +
1815 ", Scale = " + m_bScale.ToString() + ", Sign = " + IsPositive.ToString());
1818 [System.Diagnostics.Conditional("DEBUG")]
1819 private void Print(String s) {
1820 Debug.WriteLine("*** " + s + " ***");
1822 Debug.WriteLine("Numeric: Null");
1825 Debug.WriteLine("Numeric: data - " + m_data4.ToString() + ", " + m_data3.ToString() + ", " +
1826 m_data2.ToString() + ", " + m_data1.ToString());
1827 Debug.WriteLine("\tlen = " + m_bLen.ToString() + ", Prec = " + m_bPrec.ToString() +
1828 ", Scale = " + m_bScale.ToString() + ", Sign = " + IsPositive.ToString());
1831 // Set all extra uints to zero
1832 private static void ZeroToMaxLen(uint[] rgulData, int cUI4sCur) {
1833 SQLDebug.Check(rgulData.Length == x_cNumeMax, "rgulData.Length == x_cNumeMax", "Invalid array length");
1837 rgulData[1] = rgulData[2] = rgulData[3] = 0;
1841 rgulData[2] = rgulData[3] = 0;
1850 // Set all extra uints to zero
1852 private void ZeroToMaxLen(int cUI4sCur) {
1855 m_data2 = m_data3 = m_data4 = x_uiZero;
1859 m_data3 = m_data4 = x_uiZero;
1869 //Determine the number of uints needed for a numeric given a precision
1876 // The array in Shiloh. Listed here for comparison.
1877 //private static readonly byte[] rgCLenFromPrec = new byte[] {5,5,5,5,5,5,5,5,5,9,9,9,9,9,
1878 // 9,9,9,9,9,13,13,13,13,13,13,13,13,13,17,17,17,17,17,17,17,17,17,17};
1879 private static readonly byte[] rgCLenFromPrec = new byte[] {1,1,1,1,1,1,1,1,1,2,2,2,2,2,
1880 2,2,2,2,2,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4};
1882 private static byte CLenFromPrec(byte bPrec) {
1883 SQLDebug.Check(bPrec <= MaxPrecision && bPrec > 0, "bPrec <= MaxPrecision && bPrec > 0",
1884 "Invalid numeric precision");
1885 return rgCLenFromPrec[bPrec-1];
1888 // check whether is zero
1889 private bool FZero() {
1890 return(m_data1 == 0) && (m_bLen <= 1);
1893 // Find the case where we overflowed 10**38, but not 2**128
1894 private bool FGt10_38() {
1895 return m_data4 >= 0x4b3b4ca8L && m_bLen == 4 &&
1896 ((m_data4 > 0x4b3b4ca8L) || (m_data3 > 0x5a86c47aL) ||
1897 (m_data3 == 0x5a86c47aL) && (m_data2 >= 0x098a2240L));
1900 private bool FGt10_38(uint[] rglData) {
1901 SQLDebug.Check(rglData.Length == 4, "rglData.Length == 4", "Wrong array length: " + rglData.Length.ToString(CultureInfo.InvariantCulture));
1903 return rglData[3] >= 0x4b3b4ca8L &&
1904 ((rglData[3] > 0x4b3b4ca8L) || (rglData[2] > 0x5a86c47aL) ||
1905 (rglData[2] == 0x5a86c47aL) && (rglData[1] >= 0x098a2240L));
1909 // Powers of ten (used by BGetPrecI4,BGetPrecI8)
1910 private static readonly uint x_ulT1 = 10;
1911 private static readonly uint x_ulT2 = 100;
1912 private static readonly uint x_ulT3 = 1000;
1913 private static readonly uint x_ulT4 = 10000;
1914 private static readonly uint x_ulT5 = 100000;
1915 private static readonly uint x_ulT6 = 1000000;
1916 private static readonly uint x_ulT7 = 10000000;
1917 private static readonly uint x_ulT8 = 100000000;
1918 private static readonly uint x_ulT9 = 1000000000;
1919 private static readonly ulong x_dwlT10 = 10000000000;
1920 private static readonly ulong x_dwlT11 = 100000000000;
1921 private static readonly ulong x_dwlT12 = 1000000000000;
1922 private static readonly ulong x_dwlT13 = 10000000000000;
1923 private static readonly ulong x_dwlT14 = 100000000000000;
1924 private static readonly ulong x_dwlT15 = 1000000000000000;
1925 private static readonly ulong x_dwlT16 = 10000000000000000;
1926 private static readonly ulong x_dwlT17 = 100000000000000000;
1927 private static readonly ulong x_dwlT18 = 1000000000000000000;
1928 private static readonly ulong x_dwlT19 = 10000000000000000000;
1930 //------------------------------------------------------------------
1932 // Return the precision(number of significant digits) of a integer
1933 private static byte BGetPrecUI4(uint value) {
1936 // Now do the (almost) binary search
1937 if (value < x_ulT4) {
1939 ret = value >= x_ulT1 ? 2 : 1;
1941 ret = value >= x_ulT3 ? 4 : 3;
1943 else if (value < x_ulT8) {
1945 ret = value >= x_ulT5 ? 6 : 5;
1947 ret = value >= x_ulT7 ? 8 : 7;
1950 ret = value >= x_ulT9 ? 10 : 9;
1955 //------------------------------------------------------------------
1957 // Return the precision (number of significant digits) of an Int8
1958 private static byte BGetPrecUI8(uint ulU0, uint ulU1) {
1959 ulong dwlVal = ((ulong) ulU0) + (((ulong) ulU1) << 32);
1960 return BGetPrecUI8 (dwlVal);
1963 private static byte BGetPrecUI8(ulong dwlVal) {
1966 // Now do the (almost) binary search
1967 if (dwlVal < x_ulT8) {
1968 uint ulVal = (uint) dwlVal;
1970 if (ulVal < x_ulT4) {
1972 ret = (ulVal >= x_ulT1) ? 2 : 1;
1974 ret = (ulVal >= x_ulT3) ? 4 : 3;
1978 ret = (ulVal >= x_ulT5) ? 6 : 5;
1980 ret = (ulVal >= x_ulT7) ? 8 : 7;
1983 else if (dwlVal < x_dwlT16) {
1984 if (dwlVal < x_dwlT12) {
1985 if (dwlVal < x_dwlT10)
1986 ret = (dwlVal >= x_ulT9) ? 10 : 9;
1988 ret = (dwlVal >= x_dwlT11) ? 12 : 11;
1991 if (dwlVal < x_dwlT14)
1992 ret = (dwlVal >= x_dwlT13) ? 14 : 13;
1994 ret = (dwlVal >= x_dwlT15) ? 16 : 15;
1998 if (dwlVal < x_dwlT18)
1999 ret = (dwlVal >= x_dwlT17) ? 18 : 17;
2001 ret = (dwlVal >= x_dwlT19) ? 20 : 19;
2008 // This is the old precision routine. It is only used in debug code to verify that both code paths
2009 // return the same value
2014 // Determine the actual number of significant digits (precision) of a numeric
2019 // For small numerics, use simpler routines = O(n)
2020 // Else, max 3 divisions of mp by ULONG, then again simpler routine.
2023 // a byte containing the actual precision
2025 private byte BActualPrec () {
2026 if (m_bPrec == 0 || m_bLen < 1)
2034 Prec = BGetPrecUI4 (m_data1);
2036 else if (ciulU == 2) {
2037 Prec = BGetPrecUI8 (m_data1, m_data2);
2040 uint[] rgulU = new uint[4] { m_data1, m_data2, m_data3, m_data4};
2043 MpDiv1 (rgulU, ref ciulU, 1000000000, out ulRem);
2047 SQLDebug.Check (Prec == 9 || Prec == 18 || Prec == 27);
2048 Prec += BGetPrecUI8 (rgulU[0], rgulU[1]);
2051 // If number of significant digits less than scale, return scale
2052 return(Prec < m_bScale ? m_bScale : (byte)Prec);
2058 // Add ulAdd to this numeric. The result will be returned in *this.
2061 // this - IN Operand1 & OUT Result
2062 // ulAdd - IN operand2.
2064 private void AddULong(uint ulAdd) {
2065 ulong dwlAccum = (ulong) ulAdd;
2066 int iData; // which UI4 in this we are on
2067 int iDataMax = (int)m_bLen; // # of UI4s in this
2069 uint[] rguiData = new uint[4] { m_data1, m_data2, m_data3, m_data4};
2071 // Add, starting at the LS UI4 until out of UI4s or no carry
2074 dwlAccum += (ulong) rguiData[iData];
2075 rguiData[iData] = (uint)dwlAccum; // equivalent to mod x_dwlBaseUI4
2076 dwlAccum >>= 32; // equivalent to dwlAccum /= x_dwlBaseUI4;
2077 if (0 == dwlAccum) {
2078 StoreFromWorkingArray(rguiData);
2083 while (iData < iDataMax);
2085 // There is carry at the end
2087 SQLDebug.Check(dwlAccum < x_ulInt32Base, "dwlAccum < x_lInt32Base", "");
2089 // Either overflowed
2090 if (iData == x_cNumeMax)
2091 throw new OverflowException(SQLResource.ArithOverflowMessage);
2093 // Or need to extend length by 1 UI4
2094 rguiData[iData] = (uint)dwlAccum;
2097 if (FGt10_38 (rguiData))
2098 throw new OverflowException(SQLResource.ArithOverflowMessage);
2100 StoreFromWorkingArray(rguiData);
2103 // multiply by a long integer
2104 private void MultByULong(uint uiMultiplier) {
2105 int iDataMax = m_bLen; // How many UI4s currently in *this
2107 ulong dwlAccum = 0; // accumulated sum
2108 ulong dwlNextAccum = 0; // accumulation past dwlAccum
2109 int iData; // which UI4 in *This we are on.
2111 uint[] rguiData = new uint[4] { m_data1, m_data2, m_data3, m_data4};
2113 for (iData = 0; iData < iDataMax; iData++) {
2114 SQLDebug.Check(dwlAccum < x_ulInt32Base);
2116 ulong ulTemp = (ulong)rguiData[iData];
2117 dwlNextAccum = ulTemp * (ulong)uiMultiplier;
2118 dwlAccum += dwlNextAccum;
2119 if (dwlAccum < dwlNextAccum) // Overflow of int64 add
2120 dwlNextAccum = x_ulInt32Base; // how much to add to dwlAccum after div x_dwlBaseUI4
2123 rguiData[iData] = (uint)dwlAccum; // equivalent to mod x_dwlBaseUI4
2124 dwlAccum = (dwlAccum >> 32) + dwlNextAccum; // equivalent to div x_dwlBaseUI4
2128 if (dwlAccum != 0) {
2129 // Either overflowed
2130 SQLDebug.Check(dwlAccum < x_ulInt32Base, "dwlAccum < x_dwlBaseUI4", "Integer overflow");
2131 if (iDataMax == x_cNumeMax)
2132 throw new OverflowException(SQLResource.ArithOverflowMessage);
2134 // Or extend length by one uint
2135 rguiData[iDataMax] = (uint)dwlAccum;
2139 if (FGt10_38 (rguiData))
2140 throw new OverflowException(SQLResource.ArithOverflowMessage);
2142 StoreFromWorkingArray(rguiData);
2148 // Divide numeric value by a ULONG. The result will be returned
2149 // in the dividend *this.
2152 // this - IN Dividend & OUT Result
2153 // ulDivisor - IN Divisor
2154 // Returns: - OUT Remainder
2156 private uint DivByULong(uint iDivisor) {
2157 ulong dwlDivisor = (ulong) iDivisor;
2158 ulong dwlAccum = 0; //Accumulated sum
2159 uint ulQuotientCur = 0; // Value of the current UI4 of the quotient
2160 bool fAllZero = true; // All of the quotient (so far) has been 0
2161 int iData; //Which UI4 currently on
2163 // Check for zero divisor.
2164 if (dwlDivisor == 0)
2165 throw new DivideByZeroException(SQLResource.DivideByZeroMessage);
2167 // Copy into array, so that we can iterate through the data
2168 uint[] rguiData = new uint[4] { m_data1, m_data2, m_data3, m_data4};
2170 // Start from the MS UI4 of quotient, divide by divisor, placing result
2171 // in quotient and carrying the remainder.
2172 //DEVNOTE DWORDLONG sufficient accumulator since:
2173 // Accum < Divisor <= 2^32 - 1 at start each loop
2174 // initially,and mod end previous loop
2175 // Accum*2^32 < 2^64 - 2^32
2176 // multiply both side by 2^32 (x_dwlBaseUI4)
2177 // Accum*2^32 + m_rgulData < 2^64
2179 for (iData = m_bLen; iData > 0; iData--) {
2180 SQLDebug.Check(dwlAccum < dwlDivisor);
2181 dwlAccum = (dwlAccum << 32) + (ulong)(rguiData[iData-1]); // dwlA*x_dwlBaseUI4 + rglData
2182 SQLDebug.Check((dwlAccum / dwlDivisor) < x_ulInt32Base);
2183 //Update dividend to the quotient.
2184 ulQuotientCur = (uint)(dwlAccum / dwlDivisor);
2185 rguiData[iData-1] = ulQuotientCur;
2186 //Remainder to be carried to the next lower significant byte.
2187 dwlAccum = dwlAccum % dwlDivisor;
2189 // While current part of quotient still 0, reduce length
2190 if (fAllZero && (ulQuotientCur == 0)) {
2197 StoreFromWorkingArray(rguiData);
2199 // If result is 0, preserve sign but set length to 5
2205 // return the remainder
2206 SQLDebug.Check(dwlAccum < x_ulInt32Base);
2207 return(uint)dwlAccum;
2212 // Adjust number of digits to the right of the decimal point.
2213 // A positive adjustment increases the scale of the numeric value
2214 // while a negative adjustment decreases the scale. When decreasing
2215 // the scale for the numeric value, the remainder is checked and
2216 // rounded accordingly.
2218 internal void AdjustScale(int digits, bool fRound) {
2219 SQLDebug.Check(!IsNull, "!IsNull", "In AdjustScale");
2221 uint ulRem; //Remainder when downshifting
2222 uint ulShiftBase; //What to multiply by to effect scale adjust
2223 bool fNeedRound = false; //Do we really need to round?
2224 byte bNewScale, bNewPrec;
2225 int lAdjust = digits;
2227 //If downshifting causes truncation of data
2228 if (lAdjust + m_bScale < 0)
2229 throw new SqlTruncateException();
2231 //If uphifting causes scale overflow
2232 if (lAdjust + m_bScale > NUMERIC_MAX_PRECISION)
2233 throw new OverflowException(SQLResource.ArithOverflowMessage);
2235 bNewScale = (byte) (lAdjust + m_bScale);
2236 bNewPrec = (byte) (Math.Min(NUMERIC_MAX_PRECISION,Math.Max(1,lAdjust + m_bPrec)));
2239 m_bScale = bNewScale;
2242 while (lAdjust > 0) {
2243 //if lAdjust>=9, downshift by 10^9 each time, otherwise by the full amount
2245 ulShiftBase = x_rgulShiftBase[8];
2249 ulShiftBase = x_rgulShiftBase[lAdjust-1];
2252 MultByULong(ulShiftBase);
2255 else if (lAdjust < 0) {
2257 if (lAdjust <= -9) {
2258 ulShiftBase = x_rgulShiftBase[8];
2262 ulShiftBase = x_rgulShiftBase[-lAdjust - 1];
2265 ulRem = DivByULong (ulShiftBase);
2267 while (lAdjust < 0);
2269 // Do we really need to round?
2270 fNeedRound = (ulRem >= ulShiftBase/2);
2272 m_bScale = bNewScale;
2278 // After adjusting, if the result is 0 and remainder is less than 5,
2279 // set the sign to be positive and return.
2280 if (fNeedRound && fRound) {
2281 // If remainder is 5 or above, increment/decrement by 1.
2288 // Adjust scale of a SqlDecimal
2290 /// <para>[To be supplied.]</para>
2292 public static SqlDecimal AdjustScale(SqlDecimal n, int digits, bool fRound) {
2294 return SqlDecimal.Null;
2297 ret.AdjustScale(digits, fRound);
2301 // Convert to a specific precision and scale
2303 /// <para>[To be supplied.]</para>
2305 public static SqlDecimal ConvertToPrecScale(SqlDecimal n, int precision, int scale) {
2306 CheckValidPrecScale(precision, scale);
2310 return SqlDecimal.Null;
2314 int lPrecAdjust = precision - (int)ret.m_bPrec;//Adjustment to precision
2315 int lScaleAdjust = scale - (int)ret.m_bScale;//Adjustment to scale
2318 ret.AdjustScale(lScaleAdjust, true);
2320 // devnote: is that still true?
2321 //Shouldn't truncate the integer digits; BActualPrec() is an expensive
2322 //function call, so test the data length first to eliminate majority
2325 //The number of bytes storage required by the new precision
2326 byte cbWithNewPrec = CLenFromPrec((byte)precision);
2328 if (cbWithNewPrec < ret.m_bLen) {
2329 //if current actual length greater than length corresponding to bNewPrec
2330 //there must be truncating
2331 throw new SqlTruncateException();
2333 else if (cbWithNewPrec == ret.m_bLen) {
2334 //if the two lengths equal, need to check the actual precision
2335 if (precision < ret.CalculatePrecision())
2336 throw new SqlTruncateException();
2340 ret.m_bPrec = (byte)precision;
2349 // Compare the absolute value of two numerics without checking scale
2352 // this - IN Operand1
2353 // snumOp - IN Operand2
2356 // positive - |this| > |snumOp|
2357 // 0 - |this| = |snumOp|
2358 // negative - |this| < |snumOp|
2360 private int LAbsCmp(SqlDecimal snumOp) {
2362 int iData; //which UI4 we are operating on
2363 int culOp; //#of UI4s on operand
2364 int culThis; //# of UI4s in this
2366 // If one longer, it is larger
2367 culOp = snumOp.m_bLen;
2369 if (culOp != culThis)
2370 return(culThis > culOp) ? 1 : -1;
2372 uint[] rglData1 = new uint[4] {m_data1, m_data2, m_data3, m_data4};
2373 uint[] rglData2 = new uint[4] {snumOp.m_data1, snumOp.m_data2, snumOp.m_data3, snumOp.m_data4};
2375 // Loop through numeric value checking each byte for differences.
2380 if (rglData1[iData] != rglData2[iData])
2381 return((rglData1[iData] > rglData2[iData]) ? 1 : -1);
2386 // All UI4s the same, return 0.
2390 // Move multi-precision number
2391 private static void MpMove
2393 uint[] rgulS, // In | Source number
2394 int ciulS, // In | # of digits in S
2395 uint[] rgulD, // Out | Destination number
2396 out int ciulD // Out | # of digits in D
2400 SQLDebug.Check(rgulS.Length >= ciulS, "rgulS.Length >= ciulS", "Invalid array length");
2401 SQLDebug.Check(rgulD.Length >= ciulS, "rgulD.Length >= ciulS", "Invalid array length");
2403 for (int i = 0; i < ciulS; i ++)
2404 rgulD[i] = rgulS[i];
2407 // Set multi-precision number to one super-digit
2408 private static void MpSet
2410 uint[] rgulD, // Out | Number
2411 out int ciulD, // Out | # of digits in D
2412 uint iulN // In | ULONG to set
2418 // Normalize multi-precision number - remove leading zeroes
2419 private static void MpNormalize
2421 uint[] rgulU, // In | Number
2422 ref int ciulU // InOut| # of digits
2424 while (ciulU > 1 && rgulU[ciulU-1] == 0)
2428 // Multi-precision one super-digit multiply in place.
2430 // Length can increase
2431 private static void MpMul1
2433 uint[] piulD, // InOut| D
2434 ref int ciulD, // InOut| # of digits in D
2437 SQLDebug.Check(iulX > x_uiZero);
2442 for (iData = 0; iData < ciulD; iData ++) {
2443 ulong ulTemp = (ulong)piulD[iData];
2444 dwlAccum = ulCarry + ulTemp * (ulong)iulX;
2445 ulCarry = HI (dwlAccum);
2446 piulD[iData] = LO (dwlAccum);
2449 // If overflow occurs, increase precision
2451 piulD[iData] = ulCarry;
2456 // Multi-precision one super-digit divide in place.
2459 // Length of U can decrease
2460 private static void MpDiv1
2462 uint[] rgulU, // InOut| U
2463 ref int ciulU, // InOut| # of digits in U
2464 uint iulD, // In | D
2465 out uint iulR // Out | R
2467 SQLDebug.Check(rgulU.Length == x_cNumeMax);
2471 ulong ulD = (ulong)iulD;
2474 SQLDebug.Check(iulD != 0, "iulD != 0", "Divided by zero!");
2475 SQLDebug.Check(iulD > 0, "iulD > 0", "Invalid data: less than zero");
2476 SQLDebug.Check(ciulU > 0, "ciulU > 0", "No data in the array");
2480 dwlAccum = (((ulong)ulCarry) << 32) + (ulong)(rgulU[idU]);
2481 rgulU[idU] = (uint)(dwlAccum / ulD);
2482 ulCarry = (uint) (dwlAccum - (ulong)rgulU[idU] * ulD); // (ULONG) (dwlAccum % iulD)
2485 MpNormalize (rgulU, ref ciulU);
2488 internal static ulong DWL(uint lo, uint hi) {
2489 return(ulong)lo + ( ((ulong)hi) << 32 );
2492 private static uint HI(ulong x) {
2493 return(uint)(x >> 32);
2496 private static uint LO(ulong x) {
2500 // Multi-precision divide.
2503 // U and D not changed.
2504 // It is Ok for U and R to have the same location in memory,
2505 // but then U will be changed.
2506 // Assumes that there is enough room in Q and R for results.
2508 // Drawbacks of this implementation:
2509 // 1) Need one extra super-digit (ULONG) in R
2510 // 2) As it modifies D during work, then it do (probably) unnecessary
2511 // work to restore it
2512 // 3) Always get Q and R - if R is unnecessary, can be slightly faster
2513 // Most of this can be fixed if it'll be possible to have a working buffer. But
2514 // then we'll use alloca() or there will be limit on the upper size of numbers
2515 // (maybe not a problem in SQL Server).
2517 private static void MpDiv
2519 uint[] rgulU, // In | U
2520 int ciulU, // In | # of digits in U
2521 uint[] rgulD, // In | D
2522 int ciulD, // In | # of digits in D
2523 uint[] rgulQ, // Out | Q
2524 out int ciulQ, // Out | # of digits in Q
2525 uint[] rgulR, // Out | R
2526 out int ciulR // Out | # of digits in R
2528 SQLDebug.Check(ciulU > 0, "ciulU > 0", "In method MpDiv");
2529 SQLDebug.Check(ciulD > 0, "ciulD > 0", "In method MpDiv");
2530 SQLDebug.Check(rgulU.Length == x_cNumeMax);
2531 SQLDebug.Check(rgulD.Length == x_cNumeMax);
2533 // Division by zero?
2534 if (ciulD == 1 && rgulD[0] == 0) {
2538 // Check for simplest case, so it'll be fast
2539 else if (ciulU == 1 && ciulD == 1) {
2540 MpSet (rgulQ, out ciulQ, rgulU[0] / rgulD[0]);
2541 MpSet (rgulR, out ciulR, rgulU[0] % rgulD[0]);
2544 // If D > U then do not divide at all
2545 else if (ciulD > ciulU) {
2546 MpMove (rgulU, ciulU, rgulR, out ciulR); // R = U
2547 MpSet (rgulQ, out ciulQ, 0); // Q = 0
2550 // Try to divide faster - check for remaining good sizes (8 / 4, 8 / 8)
2551 else if (ciulU <= 2) {
2552 ulong dwlU, dwlD, dwlT;
2554 dwlU = DWL (rgulU[0], rgulU[1]);
2557 dwlD += ( ((ulong)rgulD[1]) << 32 );
2559 rgulQ[0] = LO (dwlT);
2560 rgulQ[1] = HI (dwlT);
2561 ciulQ = (HI (dwlT) != 0) ? 2 : 1;
2563 rgulR[0] = LO (dwlT);
2564 rgulR[1] = HI (dwlT);
2565 ciulR = (HI (dwlT) != 0) ? 2 : 1;
2568 // If we are dividing by one digit - use simpler routine
2569 else if (ciulD == 1) {
2570 MpMove (rgulU, ciulU, rgulQ, out ciulQ); // Q = U
2572 MpDiv1 (rgulQ, ref ciulQ, rgulD[0], out remainder); // Q = Q / D, R = Q % D
2573 rgulR[0] = remainder;
2577 // Worst case. Knuth, "The Art of Computer Programming", 3rd edition, vol.II, Alg.D, pg 272
2581 uint D1, ulDHigh, ulDSecond;
2585 MpMove (rgulU, ciulU, rgulR, out ciulR); // R = U
2587 ciulQ = ciulU - ciulD + 1;
2588 ulDHigh = rgulD[ciulD-1];
2590 // D1. Normalize so high digit of D >= BASE/2 - that guarantee
2591 // that QH will not be too far from the correct digit later in D3
2594 D1 = (uint)(x_ulInt32Base / ((ulong)ulDHigh + 1));
2596 MpMul1 (rgulD, ref ciulD, D1);
2597 ulDHigh = rgulD[ciulD-1];
2598 MpMul1 (rgulR, ref ciulR, D1);
2600 ulDSecond = rgulD[ciulD-2];
2601 // D2 already done - iulRindex initialized before normalization of R.
2602 // D3-D7. Loop on iulRindex - obtaining digits one-by-one, as "in paper"
2605 int iulDindex, iulRwork;
2606 ulong dwlAccum, dwlMulAccum;
2608 // D3. Calculate Q hat - estimation of the next digit
2609 dwlAccum = DWL (rgulR[iulRindex-1], rgulR[iulRindex]);
2610 if (ulDHigh == rgulR[iulRindex])
2611 QH = (uint)(x_ulInt32Base - 1);
2613 QH = (uint)(dwlAccum / ulDHigh);
2614 ulong ulTemp = (ulong)QH;
2615 RH = (uint)(dwlAccum - ulTemp * (ulong)ulDHigh);
2617 while (ulDSecond * ulTemp > DWL (rgulR[iulRindex-2], RH)) {
2619 if (RH >= (uint) - ((int) ulDHigh))
2625 // D4. Multiply and subtract: (some digits of) R -= D * QH
2626 for (dwlAccum = x_ulInt32Base, dwlMulAccum = 0, iulDindex = 0, iulRwork = iulRindex - ciulD;
2627 iulDindex < ciulD; iulDindex ++, iulRwork ++) {
2628 ulong ulTemp2 = (ulong)rgulD[iulDindex];
2629 dwlMulAccum += (ulong)QH * ulTemp2;
2630 dwlAccum += (ulong)rgulR[iulRwork] - LO (dwlMulAccum);
2631 dwlMulAccum = (ulong)(HI (dwlMulAccum));
2632 rgulR[iulRwork] = LO (dwlAccum);
2633 dwlAccum = HI (dwlAccum) + x_ulInt32Base - 1;
2635 dwlAccum += (ulong)rgulR[iulRwork] - dwlMulAccum;
2636 rgulR[iulRwork] = LO (dwlAccum);
2637 rgulQ[iulRindex-ciulD] = QH;
2639 // D5. Test remainder. Carry indicates result<0, therefore QH 1 too large
2640 if (HI (dwlAccum) == 0) {
2641 // D6. Add back - probabilty is 2**(-31). R += D. Q[digit] -= 1
2644 rgulQ[iulRindex-ciulD] = QH - 1;
2645 for (ulCarry = 0, iulDindex = 0, iulRwork = iulRindex - ciulD;
2646 iulDindex < ciulD; iulDindex ++, iulRwork ++) {
2647 dwlAccum = (ulong)rgulD[iulDindex] + (ulong)rgulR[iulRwork] + (ulong)ulCarry;
2648 ulCarry = HI (dwlAccum);
2649 rgulR[iulRwork] = LO (dwlAccum);
2651 rgulR[iulRwork] += ulCarry;
2653 // D7. Loop on iulRindex
2656 while (iulRindex >= ciulD);
2657 // Normalize results
2658 MpNormalize (rgulQ, ref ciulQ);
2660 MpNormalize (rgulR, ref ciulR);
2661 // D8. Unnormalize: Divide D and R to get result
2664 MpDiv1 (rgulD, ref ciulD, D1, out ret);
2665 MpDiv1 (rgulR, ref ciulR, D1, out ret);
2672 // Compare the value of two numerics
2674 // Complexity: O(pn) p: precision n: length
2677 // this - IN Operand1
2678 // snumOp - IN operand2
2681 // EComparison.LT - this < snumOp
2682 // EComparison.EQ - this = snumOp
2683 // EComparison.GT - this > snumOp
2685 private EComparison CompareNm
2690 snumOp.AssertValid();
2692 //Signs of the two numeric operands
2696 int iFinalResult; //Final result of comparision: positive = greater
2697 //than, 0 = equal, negative = less than
2699 //Initialize the sign values to be 1(positive) or -1(negative)
2700 Sign1 = IsPositive ? 1 : -1;
2701 Sign2 = snumOp.IsPositive ? 1 : -1;
2703 if (Sign1 != Sign2) //If different sign, the positive one is greater
2704 return Sign1 == 1 ? EComparison.GT : EComparison.LT;
2706 else { //same sign, have to compare absolute values
2707 //Temporary memory to hold the operand since it is const
2708 //but its scale may get adjusted during comparison
2710 SqlDecimal snumArg1 = this;
2711 SqlDecimal snumArg2 = snumOp;
2713 //First make the two operands the same scale if necessary
2714 ScaleDiff = ((int) m_bScale) - ((int) snumOp.m_bScale);
2716 if (ScaleDiff < 0) {
2717 //If increasing the scale of operand1 caused an overflow,
2718 //then its absolute value is greater than that of operand2.
2720 snumArg1.AdjustScale(-ScaleDiff, true);
2722 catch (OverflowException) {
2723 return(Sign1 > 0) ? EComparison.GT : EComparison.LT;
2726 else if (ScaleDiff > 0) {
2727 //If increasing the scale of operand2 caused an overflow, then
2728 //operand1's absolute value is less than that of operand2.
2730 snumArg2.AdjustScale(ScaleDiff, true);
2732 catch (OverflowException) {
2733 return(Sign1 > 0) ? EComparison.LT : EComparison.GT;
2737 //Compare the absolute value of the two numerics
2738 //Note: We are sure that scale of arguments is the same,
2739 // so LAbsCmp() will not modify its argument.
2740 int lResult = snumArg1.LAbsCmp(snumArg2);
2742 return EComparison.EQ;
2744 //if both positive, result same as result from LAbsCmp;
2745 //if both negative, result reverse of result from LAbsCmp
2746 iFinalResult = Sign1 * lResult;
2748 if (iFinalResult < 0)
2749 return EComparison.LT;
2751 return EComparison.GT;
2755 private static void CheckValidPrecScale(byte bPrec, byte bScale) {
2756 if (bPrec < 1 || bPrec > MaxPrecision || bScale < 0 || bScale > MaxScale || bScale > bPrec)
2757 throw new SqlTypeException(SQLResource.InvalidPrecScaleMessage);
2760 private static void CheckValidPrecScale(int iPrec, int iScale) {
2761 if (iPrec < 1 || iPrec > MaxPrecision || iScale < 0 || iScale > MaxScale || iScale > iPrec)
2762 throw new SqlTypeException(SQLResource.InvalidPrecScaleMessage);
2765 // Overloading comparison operators
2767 /// <para>[To be supplied.]</para>
2769 public static SqlBoolean operator==(SqlDecimal x, SqlDecimal y) {
2770 return(x.IsNull || y.IsNull) ? SqlBoolean.Null : new SqlBoolean(x.CompareNm(y) == EComparison.EQ);
2774 /// <para>[To be supplied.]</para>
2776 public static SqlBoolean operator!=(SqlDecimal x, SqlDecimal y) {
2781 /// <para>[To be supplied.]</para>
2783 public static SqlBoolean operator<(SqlDecimal x, SqlDecimal y) {
2784 return(x.IsNull || y.IsNull) ? SqlBoolean.Null : new SqlBoolean(x.CompareNm(y) == EComparison.LT);
2788 /// <para>[To be supplied.]</para>
2790 public static SqlBoolean operator>(SqlDecimal x, SqlDecimal y) {
2791 return(x.IsNull || y.IsNull) ? SqlBoolean.Null : new SqlBoolean(x.CompareNm(y) == EComparison.GT);
2795 /// <para>[To be supplied.]</para>
2797 public static SqlBoolean operator<=(SqlDecimal x, SqlDecimal y) {
2798 if (x.IsNull || y.IsNull)
2799 return SqlBoolean.Null;
2801 EComparison result = x.CompareNm(y);
2802 return new SqlBoolean(result == EComparison.LT || result == EComparison.EQ);
2807 /// <para>[To be supplied.]</para>
2809 public static SqlBoolean operator>=(SqlDecimal x, SqlDecimal y) {
2810 if (x.IsNull || y.IsNull)
2811 return SqlBoolean.Null;
2813 EComparison result = x.CompareNm(y);
2814 return new SqlBoolean(result == EComparison.GT || result == EComparison.EQ);
2819 //--------------------------------------------------
2820 // Alternative methods for overloaded operators
2821 //--------------------------------------------------
2823 // Alternative method for operator +
2824 public static SqlDecimal Add(SqlDecimal x, SqlDecimal y) {
2827 // Alternative method for operator -
2828 public static SqlDecimal Subtract(SqlDecimal x, SqlDecimal y) {
2832 // Alternative method for operator *
2833 public static SqlDecimal Multiply(SqlDecimal x, SqlDecimal y) {
2837 // Alternative method for operator /
2838 public static SqlDecimal Divide(SqlDecimal x, SqlDecimal y) {
2842 // Alternative method for operator ==
2843 public static SqlBoolean Equals(SqlDecimal x, SqlDecimal y) {
2847 // Alternative method for operator !=
2848 public static SqlBoolean NotEquals(SqlDecimal x, SqlDecimal y) {
2852 // Alternative method for operator <
2853 public static SqlBoolean LessThan(SqlDecimal x, SqlDecimal y) {
2857 // Alternative method for operator >
2858 public static SqlBoolean GreaterThan(SqlDecimal x, SqlDecimal y) {
2862 // Alternative method for operator <=
2863 public static SqlBoolean LessThanOrEqual(SqlDecimal x, SqlDecimal y) {
2867 // Alternative method for operator >=
2868 public static SqlBoolean GreaterThanOrEqual(SqlDecimal x, SqlDecimal y) {
2872 // Alternative method for conversions.
2874 public SqlBoolean ToSqlBoolean() {
2875 return (SqlBoolean)this;
2878 public SqlByte ToSqlByte() {
2879 return (SqlByte)this;
2882 public SqlDouble ToSqlDouble() {
2883 return (SqlDouble)this;
2886 public SqlInt16 ToSqlInt16() {
2887 return (SqlInt16)this;
2890 public SqlInt32 ToSqlInt32() {
2891 return (SqlInt32)this;
2894 public SqlInt64 ToSqlInt64() {
2895 return (SqlInt64)this;
2898 public SqlMoney ToSqlMoney() {
2899 return (SqlMoney)this;
2902 public SqlSingle ToSqlSingle() {
2903 return (SqlSingle)this;
2906 public SqlString ToSqlString() {
2907 return (SqlString)this;
2910 private static char ChFromDigit(uint uiDigit) {
2911 SQLDebug.Check(uiDigit < 10);
2912 return(char)(uiDigit + '0');
2915 // Store data back from rguiData[] to m_data*
2916 private void StoreFromWorkingArray(uint[] rguiData) {
2917 SQLDebug.Check(rguiData.Length == 4);
2918 m_data1 = rguiData[0];
2919 m_data2 = rguiData[1];
2920 m_data3 = rguiData[2];
2921 m_data4 = rguiData[3];
2924 private void SetToZero() {
2925 SQLDebug.Check(m_bPrec >= 1);
2931 m_bStatus = (byte) (x_bNotNull | x_bPositive);
2935 // Truncate to integer
2936 private void MakeInteger(out bool fFraction) {
2938 int iAdjust = m_bScale;
2942 while (iAdjust > 0) {
2944 ulRem = DivByULong (x_rgulShiftBase[8]);
2948 ulRem = DivByULong (x_rgulShiftBase[iAdjust-1]);
2952 // Check for remainder and set fFraction flag.
2961 // Builtin functions
2963 // Abs - absolute value
2965 /// <para>[To be supplied.]</para>
2967 public static SqlDecimal Abs(SqlDecimal n) {
2971 return SqlDecimal.Null;
2978 // Ceiling - next smallest integer greater than or equal to the numeric
2980 /// <para>[To be supplied.]</para>
2982 public static SqlDecimal Ceiling(SqlDecimal n) {
2986 return SqlDecimal.Null;
2988 if (n.m_bScale == 0)
2991 bool fFraction; //Fractional flag
2993 n.MakeInteger(out fFraction);
2995 //When the numeric has fraction and is positive, adjust by adding 1.
2996 //Otherwise return the integral part.
2997 if (fFraction && n.IsPositive) {
3001 if (n.FZero())//if result is zero, sign should be positive
3007 // Floor - next largest integer smaller or equal to the numeric
3009 /// <para>[To be supplied.]</para>
3011 public static SqlDecimal Floor(SqlDecimal n) {
3015 return SqlDecimal.Null;
3017 if (n.m_bScale == 0)
3020 bool fFraction; //Fractional flag
3022 n.MakeInteger(out fFraction);
3024 //When the numeric has fraction and is negative, subtract 1 by calling AddULong(1)
3025 //Otherwise return the integral part.
3026 if (fFraction && !n.IsPositive) {
3030 if (n.FZero())//if result is zero, sign should be positive
3036 // Sign - 1 if positive, -1 if negative
3038 /// <para>[To be supplied.]</para>
3040 public static SqlInt32 Sign(SqlDecimal n) {
3044 return SqlInt32.Null;
3046 if (n == new SqlDecimal(0))
3047 return SqlInt32.Zero;
3049 return n.IsNull ? SqlInt32.Null :
3050 (n.IsPositive ? new SqlInt32(1) : new SqlInt32(-1));
3053 private static SqlDecimal Round(SqlDecimal n, int lPosition, bool fTruncate) {
3055 return SqlDecimal.Null;
3057 if (lPosition >= 0) {
3058 //If round to the right of decimal number
3059 lPosition = Math.Min(NUMERIC_MAX_PRECISION, lPosition);
3060 if (lPosition >= n.m_bScale)
3061 return n; //No need to round
3064 //If round to the left of the decimal point
3065 lPosition = Math.Max(-NUMERIC_MAX_PRECISION, lPosition);
3067 //Return +0.00 if truncation of integer part
3068 if (lPosition < n.m_bScale - n.m_bPrec) {
3074 uint ulRem = 0; // Remainder: the highest significant digit to be truncated
3075 int lAdjust = Math.Abs(lPosition - (int)n.m_bScale); // Precision adjustment
3076 uint ulLastDivBase = 1; //
3078 //Compute the integral part of the numeric
3079 while (lAdjust > 0) {
3081 ulRem = n.DivByULong (x_rgulShiftBase[8]);
3082 ulLastDivBase = x_rgulShiftBase[8];
3086 ulRem = n.DivByULong (x_rgulShiftBase[lAdjust-1]);
3087 ulLastDivBase = x_rgulShiftBase[lAdjust-1];
3092 // The rounding only depends on the first digit after the rounding position
3093 if (ulLastDivBase > 1) {
3094 ulRem /= (ulLastDivBase / 10);
3097 //If result is zero, return
3098 if (n.FZero() && (fTruncate || ulRem < 5))
3105 // Adjust by adding 1 if remainder is larger than 5
3106 if (ulRem >= 5 && !fTruncate)
3109 // Convert back to original scale
3110 lAdjust = Math.Abs(lPosition - n.m_bScale);
3112 while (lAdjust-- > 0) {
3113 n.MultByULong(x_ulBase10);
3120 // Round - Round the numeric to a specific digit
3122 /// <para>[To be supplied.]</para>
3124 public static SqlDecimal Round(SqlDecimal n, int position) {
3126 return Round(n, position, false);
3129 // Truncate - Truncate the numeric to a specific digit
3131 /// <para>[To be supplied.]</para>
3133 public static SqlDecimal Truncate(SqlDecimal n, int position) {
3135 return Round(n, position, true);
3138 // Power - Compute the power of a numeric
3140 /// <para>[To be supplied.]</para>
3142 public static SqlDecimal Power(SqlDecimal n, double exp) {
3146 return SqlDecimal.Null;
3148 byte prec = n.Precision;
3149 int scale = n.Scale;
3150 double dBaseNum = n.ToDouble();
3152 n = new SqlDecimal(Math.Pow(dBaseNum, exp));
3153 n.AdjustScale(scale - (int)n.Scale, true);
3155 n.m_bPrec = MaxPrecision;
3162 // Compares this object to another object, returning an integer that
3163 // indicates the relationship.
3164 // Returns a value less than zero if this < object, zero if this = object,
3165 // or a value greater than zero if this > object.
3166 // null is considered to be less than any instance.
3167 // If object is not of same type, this method throws an ArgumentException.
3169 /// <para>[To be supplied.]</para>
3171 public int CompareTo(Object value) {
3172 if (value is SqlDecimal) {
3173 SqlDecimal i = (SqlDecimal)value;
3175 return CompareTo(i);
3177 throw ADP.WrongType(value.GetType(), typeof(SqlDecimal));
3180 public int CompareTo(SqlDecimal value) {
3181 // If both Null, consider them equal.
3182 // Otherwise, Null is less than anything.
3184 return value.IsNull ? 0 : -1;
3185 else if (value.IsNull)
3188 if (this < value) return -1;
3189 if (this > value) return 1;
3193 // Compares this instance with a specified object
3195 /// <para>[To be supplied.]</para>
3197 public override bool Equals(Object value) {
3198 if (!(value is SqlDecimal)) {
3202 SqlDecimal i = (SqlDecimal)value;
3204 if (i.IsNull || IsNull)
3205 return (i.IsNull && IsNull);
3207 return (this == i).Value;
3210 // For hashing purpose
3212 /// <para>[To be supplied.]</para>
3214 public override int GetHashCode() {
3218 SqlDecimal ssnumTemp;
3221 // First, "normalize" numeric, so that values with different
3222 // scale/precision will have the same representation.
3224 lActualPrec = ssnumTemp.CalculatePrecision();
3225 ssnumTemp.AdjustScale(NUMERIC_MAX_PRECISION - lActualPrec, true);
3227 // Now evaluate the hash
3228 int cDwords = ssnumTemp.m_bLen;
3232 // Size of CRC window (hashing bytes, ssstr, sswstr, numeric)
3233 const int x_cbCrcWindow = 4;
3234 // const int iShiftVal = (sizeof ulValue) * (8*sizeof(char)) - x_cbCrcWindow;
3235 const int iShiftVal = 4 * 8 - x_cbCrcWindow;
3237 int[] rgiData = ssnumTemp.Data;
3239 for (int i = 0; i < cDwords; i++)
3241 ulHi = (ulValue >> iShiftVal) & 0xff;
3242 ulValue <<= x_cbCrcWindow;
3243 ulValue = ulValue ^ rgiData[i] ^ ulHi;
3249 /// <para>[To be supplied.]</para>
3251 XmlSchema IXmlSerializable.GetSchema() { return null; }
3254 /// <para>[To be supplied.]</para>
3256 void IXmlSerializable.ReadXml(XmlReader reader) {
3257 string isNull = reader.GetAttribute("nil", XmlSchema.InstanceNamespace);
3258 if (isNull != null && XmlConvert.ToBoolean(isNull)) {
3259 // VSTFDevDiv# 479603 - SqlTypes read null value infinitely and never read the next value. Fix - Read the next value.
3260 reader.ReadElementString();
3261 m_bStatus = (byte) (x_bReverseNullMask & m_bStatus);
3264 SqlDecimal dec = Parse(reader.ReadElementString());
3265 this.m_bStatus = dec.m_bStatus;
3266 this.m_bLen = dec.m_bLen;
3267 this.m_bPrec = dec.m_bPrec;
3268 this.m_bScale = dec.m_bScale;
3269 this.m_data1 = dec.m_data1;
3270 this.m_data2 = dec.m_data2;
3271 this.m_data3 = dec.m_data3;
3272 this.m_data4 = dec.m_data4;
3277 /// <para>[To be supplied.]</para>
3279 void IXmlSerializable.WriteXml(XmlWriter writer) {
3281 writer.WriteAttributeString("xsi", "nil", XmlSchema.InstanceNamespace, "true");
3284 writer.WriteString(ToString());
3289 /// <para>[To be supplied.]</para>
3291 public static XmlQualifiedName GetXsdType(XmlSchemaSet schemaSet) {
3292 return new XmlQualifiedName("decimal", XmlSchema.Namespace);
3295 // These values are defined at last, because they need to call ctors, which use other
3296 // constant values. Those constants must be defined before callint ctor.
3299 /// <para>[To be supplied.]</para>
3301 public static readonly SqlDecimal Null = new SqlDecimal(true);
3304 /// <para>[To be supplied.]</para>
3306 public static readonly SqlDecimal MinValue = SqlDecimal.Parse("-99999999999999999999999999999999999999");
3308 /// <para>[To be supplied.]</para>
3310 public static readonly SqlDecimal MaxValue = SqlDecimal.Parse("99999999999999999999999999999999999999");
3314 } // namespace System.Data.SqlTypes