29c4f869a8b3d5b291800787b1855480e399096c
[mono.git] / mcs / class / referencesource / System.Data / System / Data / SQLTypes / SQLDecimal.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="SqlDecimal.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 //  </copyright>
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 //------------------------------------------------------------------------------
10
11 //**************************************************************************
12 // @File: SqlNumeric.cs
13 //
14 // Create by:    JunFang
15 // @Owner:      JunFang
16 //
17 // Purpose: Implementation of SqlMoney which is equivalent to
18 //            data type "numeric" and "decimal" in SQL Server
19 //
20 // Notes:
21 //
22 // History:
23 //
24 //    @Version: Yukon
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
28 //                        objects.
29 //
30 //   09/17/99  JunFang    Created and implemented as first drop.
31 //
32 // @EndHeader@
33 //**************************************************************************
34
35 using System;
36 using System.Data.Common;
37 using System.Diagnostics;
38 using System.Globalization;
39 using System.Runtime.InteropServices;
40 using System.Xml;
41 using System.Xml.Schema;
42 using System.Xml.Serialization;
43
44 namespace System.Data.SqlTypes {
45
46     /// <devdoc>
47     ///    <para>
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.
50     ///    </para>
51     /// </devdoc>
52     [Serializable]
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];
62
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;
71
72         private static readonly byte NUMERIC_MAX_PRECISION = 38;            // Maximum precision of numeric
73         /// <devdoc>
74         ///    <para>[To be supplied.]</para>
75         /// </devdoc>
76         public  static readonly byte MaxPrecision = NUMERIC_MAX_PRECISION;  // max SS precision
77         /// <devdoc>
78         ///    <para>[To be supplied.]</para>
79         /// </devdoc>
80         public  static readonly byte MaxScale = NUMERIC_MAX_PRECISION;      // max SS scale
81
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);
86
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);
91
92         private static readonly uint    x_uiZero            = (uint) 0;
93
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)
98
99         internal static readonly ulong   x_llMax            = Int64.MaxValue;   // Max of Int64
100
101         private static readonly uint    x_ulBase10          = 10;
102
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
108
109         private static readonly byte    x_cNumeDivScaleMin = 6;     // Minimum result scale of numeric division
110
111         // Array of multipliers for lAdjust and Ceiling/Floor.
112         private static readonly uint[] x_rgulShiftBase = new uint[9] {
113             10,
114             10 * 10,
115             10 * 10 * 10,
116             10 * 10 * 10 * 10,
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
122         };
123
124 #region DecimalHelperTableGenerator
125 /*
126         // the code below will generate the DecimalHelpers tables
127         static private string[] HelperNames = {
128             "DecimalHelpersLo", "DecimalHelpersMid", "DecimalHelpersHi", "DecimalHelpersHiHi",
129         };
130
131
132         static private void DumpDecimalHelperParts(int index)
133         {
134             SqlDecimal sqlDecimalValue = 10;    // start precision=2
135
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;
141                 }
142             }
143             sqlDecimalValue = SqlDecimal.MaxValue;
144             int[] data = sqlDecimalValue.Data;
145             UInt32[] udata = { (UInt32)data[0], (UInt32)data[1], (UInt32)data[2], (UInt32)data[3]};
146             bool carry = true;
147             for (int i = 0; i < 4; i++){
148                 if (carry){
149                     carry = (++udata[i] == 0);
150                 }
151             }
152             Console.WriteLine("    0x{0,8:x8}, // precision:{1}+1, value:{2}+1", udata[index], SqlDecimal.MaxPrecision, SqlDecimal.MaxValue.ToString());
153
154             Console.WriteLine("};");
155             Console.WriteLine();
156         }
157
158
159         static public void CreateDecimalHelperTable()
160         {
161             for (int i = 0; i < 4; i++)
162             {
163                 DumpDecimalHelperParts(i);
164             }
165         }
166
167 */
168 #endregion
169
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
210         };
211
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
251         };
252
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
292         };
293
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
333         };
334 #endregion
335
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.
341         //
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
344         //
345         private const int HelperTableStartIndexLo = 5;
346         private const int HelperTableStartIndexMid = 15;
347         private const int HelperTableStartIndexHi = 24;
348         private const int HelperTableStartIndexHiHi = 33;
349
350         private byte CalculatePrecision() {
351             int tableIndex;
352             byte precision;
353             UInt32[] decimalHelpers;
354             UInt32 decimalPart;
355
356             if (m_data4 != 0) {
357                 tableIndex = HelperTableStartIndexHiHi;
358                 decimalHelpers = DecimalHelpersHiHi;
359                 decimalPart = m_data4;
360             }
361             else if (m_data3 != 0) {
362                 tableIndex = HelperTableStartIndexHi;
363                 decimalHelpers = DecimalHelpersHi;
364                 decimalPart = m_data3;
365             }
366             else if (m_data2 != 0) {
367                 tableIndex = HelperTableStartIndexMid;
368                 decimalHelpers = DecimalHelpersMid;
369                 decimalPart = m_data2;
370             }
371             else {
372                 tableIndex = HelperTableStartIndexLo;
373                 decimalHelpers = DecimalHelpersLo;
374                 decimalPart = m_data1;
375             }
376
377
378             // this code will move the index no more than -2 -2 -1 (-5) or +2 +1 +1 (+4)
379             // from the initial position
380             //
381             if (decimalPart < decimalHelpers[tableIndex]) {
382                 tableIndex -= 2;
383                 if (decimalPart < decimalHelpers[tableIndex]) {
384                     tableIndex -= 2;
385                     if (decimalPart < decimalHelpers[tableIndex]) {
386                         tableIndex -= 1;
387                     }
388                     else {
389                         tableIndex += 1;
390                     }
391                 }
392                 else {
393                     tableIndex += 1;
394                 }
395             }
396             else {
397                 tableIndex += 2;
398                 if (decimalPart < decimalHelpers[tableIndex]) {
399                     tableIndex -= 1;
400                 }
401                 else {
402                     tableIndex += 1;
403                 }
404             }
405             if (decimalPart >= decimalHelpers[tableIndex]) {
406                 tableIndex += 1;
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.
412                     tableIndex += 1;
413                 }
414             }
415
416             precision = (byte)(tableIndex + 1);
417             if (precision > 1) {
418                 // not done yet
419                 // tableIndex may still be off by one since we didn't look at the lower words
420                 //
421                 if (VerifyPrecision((byte)(precision-1))) {
422                     precision -= 1;
423                 }
424             }
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?");
427
428             // adjust the precision
429             // This might not be correct but is to our best knowledge
430             precision = Math.Max(precision, m_bScale);
431 #if DEBUG
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
436
437             Debug.Assert (precision==bActualPrecision,String.Format((IFormatProvider)null, "CalculatePrecision={0}, BActualPrec={1}. Results must be equal!", precision, bActualPrecision));
438 #endif
439             return precision;
440         }
441
442         // VerifyPrecision
443         //
444         // returns true if the current value is less or equal than the max value of the
445         // supplied precision.
446         //
447         private bool VerifyPrecision (byte precision) {
448             Debug.Assert(precision>0,"Precision cannot be less than 1");
449             Debug.Assert(precision<=MaxPrecision, "Precision > MaxPrecision");
450
451             int  tableIndex = checked((int)precision -1);
452             if (m_data4 < DecimalHelpersHiHi[tableIndex]) {
453                 return true;
454             }
455             else if (m_data4 == DecimalHelpersHiHi[tableIndex]) {
456                 if (m_data3 < DecimalHelpersHi[tableIndex]) {
457                     return true;
458                 }
459                 else if (m_data3 == DecimalHelpersHi[tableIndex]) {
460                     if (m_data2 < DecimalHelpersMid[tableIndex]) {
461                         return true;
462                     }
463                     else if (m_data2 == DecimalHelpersMid[tableIndex]) {
464                         if (m_data1 < DecimalHelpersLo[tableIndex]) {
465                             return true;
466                         }
467                     }
468                 }
469             }
470             return false;
471         }
472
473
474
475         // constructor
476         // construct a Null
477         private SqlDecimal(bool fNull) {
478             m_bLen =
479             m_bPrec =
480             m_bScale = (byte)0;
481             m_bStatus = 0;
482             m_data1 =
483             m_data2 =
484             m_data3 =
485             m_data4 = x_uiZero;
486         }
487
488         /// <devdoc>
489         ///    <para>[To be supplied.]</para>
490         /// </devdoc>
491         public SqlDecimal(Decimal value) {
492             // set the null bit
493             m_bStatus = x_bNotNull;
494
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++;
498
499             // m_data3 = *pInt++; // high part
500             // m_data1 = *pInt++; // lo part
501             // m_data2 = *pInt++; // mid part
502
503             int[] bits = Decimal.GetBits(value);
504
505             UInt32 sgnscl = (UInt32)bits[3];
506             m_data1 = (UInt32)bits[0];
507             m_data2 = (UInt32)bits[1];
508             m_data3 = (UInt32)bits[2];
509             m_data4 = x_uiZero;
510
511             // set the sign bit
512             m_bStatus |= ((sgnscl & 0x80000000) == 0x80000000)? x_bNegative:(byte)0;
513
514             if (m_data3 != 0)
515                 m_bLen = 3;
516             else if (m_data2 != 0)
517                 m_bLen = 2;
518             else
519                 m_bLen = 1;
520
521             // Get the scale info from Decimal
522             m_bScale = (byte)((int)(sgnscl & 0xff0000) >>16);
523
524             // initialize precision
525             m_bPrec = 0; // The this object cannot be used before all of its fields are assigned to
526
527
528             m_bPrec = CalculatePrecision();
529 // CalculatePrecision adjusts!
530 //            if (m_bPrec < m_bScale)
531 //                m_bPrec = m_bScale;
532         }
533
534         /// <devdoc>
535         ///    <para>[To be supplied.]</para>
536         /// </devdoc>
537         public SqlDecimal(int value) {
538             // set the null bit
539             m_bStatus = x_bNotNull;
540
541             uint uiValue = (uint) value;
542
543             // set the sign bit
544             if (value < 0) {
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);
549             }
550
551             // set the data
552             m_data1 = uiValue;
553             m_data2 = m_data3 = m_data4 = x_uiZero;
554
555             m_bLen = 1;
556             m_bPrec = BGetPrecUI4(m_data1);
557             m_bScale = 0;
558         }
559
560         /// <devdoc>
561         ///    <para>[To be supplied.]</para>
562         /// </devdoc>
563         public SqlDecimal(long value) {
564             // set the null bit
565             m_bStatus = x_bNotNull;
566
567             ulong dwl = (ulong)value;
568
569             // set the sign bit
570             if (value < 0) {
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);
575             }
576
577             // Copy DWL into bottom 2 UI4s of numeric
578             m_data1 = (uint)dwl;
579             m_data2 = (uint)(dwl >> 32);
580             m_data3 = m_data4 = 0;
581
582             // Trim any leading zero from the length
583             m_bLen = (byte)((m_data2 == 0) ? 1 : 2);
584
585             m_bPrec = BGetPrecUI8(dwl);
586             m_bScale = 0;
587
588             AssertValid();
589         }
590
591         /// <devdoc>
592         ///    <para>[To be supplied.]</para>
593         /// </devdoc>
594         public SqlDecimal(byte bPrecision, byte bScale, bool fPositive, int[] bits) {
595             CheckValidPrecScale(bPrecision, bScale);
596             if (bits == null)
597                 throw new ArgumentNullException("bits");
598             else if (bits.Length != 4)
599                 throw new ArgumentException(SQLResource.InvalidArraySizeMessage, "bits");
600
601             m_bPrec = bPrecision;
602             m_bScale = bScale;
603             m_data1 = (uint)bits[0];
604             m_data2 = (uint)bits[1];
605             m_data3 = (uint)bits[2];
606             m_data4 = (uint)bits[3];
607             m_bLen = 1;
608             for (int i = 3; i >= 0; i --) {
609                 if (bits[i] != 0) {
610                     m_bLen = (byte)(i + 1);
611                     break;
612                 }
613             }
614
615             // set the null bit
616             m_bStatus = x_bNotNull;
617
618             // set the sign bit
619             if (!fPositive) {
620                 m_bStatus |= x_bNegative;
621             }
622
623             // If result is -0, adjust sign to positive.
624             if (FZero())
625                 SetPositive();
626
627             if (bPrecision < CalculatePrecision())
628                 throw new OverflowException(SQLResource.ArithOverflowMessage);
629         }
630
631         /// <devdoc>
632         ///    <para>[To be supplied.]</para>
633         /// </devdoc>
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;
637             m_bScale = bScale;
638
639             m_data1 = (uint)data1;
640             m_data2 = (uint)data2;
641             m_data3 = (uint)data3;
642             m_data4 = (uint)data4;
643
644             m_bLen = 1;
645             if (data4 == 0)
646                 if (data3 == 0)
647                     if (data2 == 0)
648                         m_bLen = 1;
649                     else
650                         m_bLen = 2;
651                 else
652                     m_bLen = 3;
653             else
654                 m_bLen = 4;
655
656             // set the null bit
657             m_bStatus = x_bNotNull;
658
659             // set the sign bit
660             if (!fPositive) {
661                 m_bStatus |= x_bNegative;
662             }
663
664             // If result is -0, adjust sign to positive.
665             if (FZero())
666                 SetPositive();
667
668             if (bPrecision < CalculatePrecision())
669                 throw new OverflowException(SQLResource.ArithOverflowMessage);
670         }
671
672         /// <devdoc>
673         ///    <para>[To be supplied.]</para>
674         /// </devdoc>
675         public SqlDecimal(double dVal) : this(false) {
676             // set the null bit
677             m_bStatus = x_bNotNull;
678
679             // Split double to sign, integer, and fractional parts
680             if (dVal < 0) {
681                 dVal = -dVal;
682                 m_bStatus |= x_bNegative;
683             }
684
685             // If it will not fit into numeric(NUMERIC_MAX_PRECISION,0), overflow.
686             if (dVal >= DMAX_NUME)
687                 throw new OverflowException(SQLResource.ArithOverflowMessage);
688
689             double dInt = Math.Floor(dVal);
690             double dFrac = dVal - dInt;
691
692             m_bPrec  = NUMERIC_MAX_PRECISION;
693             m_bLen = 1;
694             if (dInt > 0.0) {
695                 dVal = Math.Floor (dInt / DUINT_BASE);
696                 m_data1 = (uint)(dInt - dVal * DUINT_BASE);
697                 dInt = dVal;
698
699                 if (dInt > 0.0) {
700                     dVal = Math.Floor (dInt / DUINT_BASE);
701                     m_data2 = (uint)(dInt - dVal * DUINT_BASE);
702                     dInt = dVal;
703                     m_bLen ++;
704
705                     if (dInt > 0.0) {
706                         dVal = Math.Floor (dInt / DUINT_BASE);
707                         m_data3 = (uint)(dInt - dVal * DUINT_BASE);
708                         dInt = dVal;
709                         m_bLen ++;
710
711                         if (dInt > 0.0) {
712                             dVal = Math.Floor (dInt / DUINT_BASE);
713                             m_data4 = (uint) (dInt - dVal * DUINT_BASE);
714                             dInt = dVal;
715                             m_bLen ++;
716                         }
717                     }
718                 }
719             }
720
721             uint ulLen, ulLenDelta;
722             uint ulTemp;
723
724             // Get size of the integer part
725             ulLen = FZero() ? 0 : (uint)CalculatePrecision();
726             SQLDebug.Check(ulLen <= NUMERIC_MAX_PRECISION, "ulLen <= NUMERIC_MAX_PRECISION", "");
727
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;
732                 do {
733                     ulTemp = DivByULong (10);
734                     ulWrk --;
735                 }
736                 while (ulWrk > 0);
737                 ulWrk = ulLen - DBL_DIG;
738
739                 // Round, if necessary. # of digits can change. Cannot be overflow.
740                 if (ulTemp >= 5) {
741                     AddULong (1);
742                     ulLen = CalculatePrecision() + ulWrk;
743                 }
744
745                 // Multiply back
746                 do {
747                     MultByULong (10);
748                     ulWrk --;
749                 }
750                 while (ulWrk > 0);
751             }
752
753             m_bScale = (byte)(ulLen < DBL_DIG ? DBL_DIG - ulLen : 0);
754             m_bPrec = (byte)(ulLen + m_bScale);
755
756             // Add meaningful fractional part - max 9 digits per iteration
757             if (m_bScale > 0) {
758                 ulLen = m_bScale;
759                 do {
760                     ulLenDelta = (ulLen >= 9) ? 9 : ulLen;
761
762                     dFrac *= (double) x_rgulShiftBase[(int)ulLenDelta-1];
763                     ulLen -= ulLenDelta;
764                     MultByULong (x_rgulShiftBase[(int)ulLenDelta-1]);
765                     AddULong ((uint) dFrac);
766                     dFrac -= Math.Floor (dFrac);
767                 }
768                 while (ulLen > 0);
769             }
770
771             // Round, if necessary
772             if (dFrac >= 0.5) {
773                 AddULong (1);
774             }
775
776             if (FZero())
777                 SetPositive();
778
779             AssertValid();
780         }
781
782         private SqlDecimal(uint[] rglData, byte bLen, byte bPrec, byte bScale, bool fPositive) {
783             CheckValidPrecScale(bPrec, bScale);
784             SQLDebug.Check(rglData.Length >= 4);
785
786             m_bLen = bLen;
787             m_bPrec = bPrec;
788             m_bScale = bScale;
789             m_data1 = rglData[0];
790             m_data2 = rglData[1];
791             m_data3 = rglData[2];
792             m_data4 = rglData[3];
793
794             // set the null bit
795             m_bStatus = x_bNotNull;
796
797             // set the sign bit
798             if (!fPositive) {
799                 m_bStatus |= x_bNegative;
800             }
801
802             // If result is -0, adjust sign to positive.
803             if (FZero())
804                 SetPositive();
805         }
806
807
808         // INullable
809         /// <devdoc>
810         ///    <para>[To be supplied.]</para>
811         /// </devdoc>
812         public bool IsNull {
813             get { return(m_bStatus & x_bNullMask) == x_bIsNull;}
814         }
815
816         /// <devdoc>
817         ///    <para>[To be supplied.]</para>
818         /// </devdoc>
819         public Decimal Value {
820             get { return ToDecimal();}
821         }
822
823         /// <devdoc>
824         ///    <para>[To be supplied.]</para>
825         /// </devdoc>
826         public bool IsPositive {
827             get {
828                 if (IsNull)
829                     throw new SqlNullValueException();
830                 return(m_bStatus & x_bSignMask) == x_bPositive;
831             }
832         }
833
834         private void SetPositive() {
835             SQLDebug.Check(!IsNull);
836             m_bStatus = (byte)(m_bStatus & x_bReverseSignMask);
837         }
838
839         private void SetSignBit(bool fPositive) {
840             SQLDebug.Check(!IsNull);
841             m_bStatus = (byte)(fPositive ? (m_bStatus & x_bReverseSignMask) : (m_bStatus | x_bNegative));
842         }
843
844         /// <devdoc>
845         ///    <para>[To be supplied.]</para>
846         /// </devdoc>
847         public byte Precision {
848             get {
849                 if (IsNull)
850                     throw new SqlNullValueException();
851                 return m_bPrec;
852             }
853         }
854
855         /// <devdoc>
856         ///    <para>[To be supplied.]</para>
857         /// </devdoc>
858         public byte Scale {
859             get {
860                 if (IsNull)
861                     throw new SqlNullValueException();
862                 return m_bScale;
863             }
864         }
865
866         /// <devdoc>
867         ///    <para>[To be supplied.]</para>
868         /// </devdoc>
869         public int[] Data {
870             get {
871                 if (IsNull)
872                     throw new SqlNullValueException();
873                 return new int[4] { (int)m_data1, (int)m_data2, (int)m_data3, (int)m_data4};
874             }
875         }
876
877         /// <devdoc>
878         ///    <para>[To be supplied.]</para>
879         /// </devdoc>
880         public byte[] BinData {
881             get {
882                 if (IsNull)
883                     throw new SqlNullValueException();
884
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);
891                 data1 >>= 8;
892                 rgBinData[1] = (byte)(data1 & 0xff);
893                 data1 >>= 8;
894                 rgBinData[2] = (byte)(data1 & 0xff);
895                 data1 >>= 8;
896                 rgBinData[3] = (byte)(data1 & 0xff);
897                 rgBinData[4] = (byte)(data2 & 0xff);
898                 data2 >>= 8;
899                 rgBinData[5] = (byte)(data2 & 0xff);
900                 data2 >>= 8;
901                 rgBinData[6] = (byte)(data2 & 0xff);
902                 data2 >>= 8;
903                 rgBinData[7] = (byte)(data2 & 0xff);
904                 rgBinData[8] = (byte)(data3 & 0xff);
905                 data3 >>= 8;
906                 rgBinData[9] = (byte)(data3 & 0xff);
907                 data3 >>= 8;
908                 rgBinData[10] = (byte)(data3 & 0xff);
909                 data3 >>= 8;
910                 rgBinData[11] = (byte)(data3 & 0xff);
911                 rgBinData[12] = (byte)(data4 & 0xff);
912                 data4 >>= 8;
913                 rgBinData[13] = (byte)(data4 & 0xff);
914                 data4 >>= 8;
915                 rgBinData[14] = (byte)(data4 & 0xff);
916                 data4 >>= 8;
917                 rgBinData[15] = (byte)(data4 & 0xff);
918
919                 return rgBinData;
920             }
921         }
922
923         /// <devdoc>
924         ///    <para>[To be supplied.]</para>
925         /// </devdoc>
926         public override String ToString() {
927             if (IsNull)
928                 return SQLResource.NullString;
929             AssertValid();
930
931             // Make local copy of data to avoid modifying input.
932             uint[]  rgulNumeric = new uint[4] { m_data1, m_data2, m_data3, m_data4};
933             int     culLen = m_bLen;
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
937
938             int     iDigits = 0;//Number of significant digits
939             uint    ulRem; //Remainder of a division by x_ulBase10, i.e.,least significant digit
940
941             // Build the final numeric string by inserting the sign, reversing
942             // the order and inserting the decimal number at the correct position
943
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);
949             }
950
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);
955             }
956
957
958             int uiResultLen = 0;
959             int iCurChar = 0;
960             char[] szResult;
961
962             // Increment the result length if scale > 0 (need to add '.')            
963             if (m_bScale > 0) {
964                 uiResultLen = 1;
965             }
966
967             if (IsPositive) {
968                 szResult = new char[uiResultLen + iDigits];
969             }
970             else {
971                 // Increment the result length if negative (need to add '-')            
972                 szResult = new char[uiResultLen + iDigits + 1];
973                 szResult[iCurChar ++] = '-';
974             }          
975             
976             while (iDigits > 0) {
977                 if (iDigits-- == m_bScale)
978                     szResult[iCurChar ++] = '.';
979
980                 szResult[iCurChar ++] = pszTmp[iDigits];
981             }
982
983             AssertValid();
984
985             return new String(szResult);
986         }
987
988         /// <devdoc>
989         ///    <para>[To be supplied.]</para>
990         /// </devdoc>
991         public static SqlDecimal Parse(String s) {
992             if (s == null)
993                 throw new ArgumentNullException("s");
994
995             if (s == SQLResource.NullString)
996                 return SqlDecimal.Null;
997
998             SqlDecimal snResult = SqlDecimal.Null;
999
1000             char[] rgwchStr = s.ToCharArray();
1001             int cwchStr = rgwchStr.Length;
1002
1003             int        iData;            //index to string
1004             char    usChar;            //current value in string
1005             int        lDecPnt = -1;    //position of decimal point in string
1006             int     iCurChar = 0;
1007
1008             //Must initialize precision and scale to valid values
1009             snResult.m_bPrec  = 1;
1010             snResult.m_bScale = 0;
1011
1012             //Must initialize *this to zero
1013             snResult.SetToZero ();
1014
1015             // Trim trailing blanks.
1016             while (cwchStr != 0 && rgwchStr[cwchStr-1] == ' ')
1017                 cwchStr--;
1018
1019             // If string contains only spaces, stop
1020             if (cwchStr == 0)
1021                 throw new FormatException(SQLResource.FormatMessage);
1022
1023             // Trim leading blanks.
1024             while (rgwchStr[iCurChar] == ' ') {
1025                 iCurChar++;
1026                 cwchStr--;
1027             }
1028
1029             // Get sign for numeric value.
1030             if (rgwchStr[iCurChar] == '-') {
1031                 snResult.SetSignBit(false);
1032                 iCurChar++;
1033                 cwchStr--;
1034             }
1035             else {
1036                 snResult.SetSignBit(true);
1037                 if (rgwchStr[iCurChar] == '+') {
1038                     iCurChar++;
1039                     cwchStr--;
1040                 }
1041             }
1042
1043             // Hack: Check for "0.". If so, replace by ".0".
1044             while ((cwchStr > 2) && (rgwchStr[iCurChar] == '0')) {
1045                 iCurChar++;
1046                 cwchStr--;
1047             }
1048             if (2 == cwchStr && '0' == rgwchStr[iCurChar] && '.' == rgwchStr[iCurChar + 1]) {
1049                 rgwchStr[iCurChar] = '.';
1050                 rgwchStr[iCurChar + 1] = '0';
1051             }
1052
1053             // Invalid string?
1054             if (cwchStr == 0 || cwchStr > NUMERIC_MAX_PRECISION + 1)
1055                 throw new FormatException(SQLResource.FormatMessage);
1056
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')) {
1060                 iCurChar++;
1061                 cwchStr--;
1062             }
1063
1064             // Convert string to numeric value by looping through input string.
1065             for(iData=0; iData < cwchStr; iData++)
1066             {
1067                 usChar = rgwchStr[iCurChar];
1068                 iCurChar ++;
1069
1070                 if (usChar >= '0' && usChar <= '9')
1071                     usChar -= '0';
1072                 else if (usChar == '.' && lDecPnt < 0) {
1073                     lDecPnt = iData;
1074                     continue;
1075                 }
1076                 else
1077                     throw new FormatException(SQLResource.FormatMessage);
1078
1079                 snResult.MultByULong(x_ulBase10);
1080                 snResult.AddULong(usChar);
1081             }
1082
1083             // Save precision and scale.
1084             if (lDecPnt < 0) {
1085                 snResult.m_bPrec  = (byte)iData;
1086                 snResult.m_bScale = 0;
1087             }
1088             else {
1089                 snResult.m_bPrec =  (byte)(iData - 1);
1090                 snResult.m_bScale = (byte) (snResult.m_bPrec - lDecPnt);
1091             }
1092
1093             //Check for overflow condition
1094             if (snResult.m_bPrec > NUMERIC_MAX_PRECISION)
1095                 throw new FormatException(SQLResource.FormatMessage);
1096
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);
1101
1102             // If result is -0, adjust sign to positive.
1103             if (snResult.FZero())
1104                 snResult.SetPositive();
1105
1106             snResult.AssertValid();
1107
1108             return snResult;
1109         }
1110
1111         /// <devdoc>
1112         ///    <para>[To be supplied.]</para>
1113         /// </devdoc>
1114         public double ToDouble() {
1115             if (IsNull)
1116                 throw new SqlNullValueException();
1117
1118             double dRet = 0.0;
1119
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;
1124
1125             dRet /= System.Math.Pow(10.0, m_bScale);
1126
1127             return IsPositive ? dRet : - dRet;
1128         }
1129
1130         private Decimal ToDecimal() {
1131             if (IsNull)
1132                 throw new SqlNullValueException();
1133
1134             if ((int)m_data4 != 0 || m_bScale > 28)
1135                 throw new OverflowException(SQLResource.ConversionOverflowMessage);
1136
1137             return new Decimal((int)m_data1, (int)m_data2, (int)m_data3, !IsPositive, m_bScale);
1138         }
1139
1140         // Implicit conversion from Decimal to SqlDecimal
1141         /// <devdoc>
1142         ///    <para>[To be supplied.]</para>
1143         /// </devdoc>
1144         public static implicit operator SqlDecimal(Decimal x) {
1145             return new SqlDecimal(x);
1146         }
1147
1148         // Explicit conversion from Double to SqlDecimal
1149         public static explicit operator SqlDecimal(double x) {
1150             return new SqlDecimal(x);
1151         }
1152
1153         // Implicit conversion from long to SqlDecimal
1154         public static implicit operator SqlDecimal(long x) {
1155             return new SqlDecimal(new Decimal(x));
1156         }
1157
1158         // Explicit conversion from SqlDecimal to Decimal. Throw exception if x is Null.
1159         /// <devdoc>
1160         ///    <para>[To be supplied.]</para>
1161         /// </devdoc>
1162         public static explicit operator Decimal(SqlDecimal x) {
1163             return x.Value;
1164         }
1165
1166
1167         // Unary operators
1168         /// <devdoc>
1169         ///    <para>[To be supplied.]</para>
1170         /// </devdoc>
1171         public static SqlDecimal operator -(SqlDecimal x) {
1172             if (x.IsNull)
1173                 return Null;
1174             else {
1175                 SqlDecimal s = x;
1176                 if (s.FZero())
1177                     s.SetPositive();
1178                 else
1179                     s.SetSignBit(!s.IsPositive);
1180                 return s;
1181             }
1182         }
1183
1184
1185         // Binary operators
1186
1187         // Arithmetic operators
1188         /// <devdoc>
1189         ///    <para>[To be supplied.]</para>
1190         /// </devdoc>
1191         public static SqlDecimal operator +(SqlDecimal x, SqlDecimal y) {
1192             if (x.IsNull || y.IsNull)
1193                 return Null;
1194
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
1208
1209
1210             x.AssertValid();
1211             y.AssertValid();
1212
1213             fMySignPos = x.IsPositive;
1214             fOpSignPos = y.IsPositive;
1215
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;
1220
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);
1224
1225             // Calculate the scale of the result.
1226             ResScale = Math.Max(MyScale, OpScale);
1227             SQLDebug.Check (ResScale <= MaxScale);
1228
1229             // Calculate the precision of the result.
1230             // Add 1 for final carry.
1231             ResPrec = ResInteger + ResScale + 1;
1232             ResPrec = Math.Min(MaxPrecision, ResPrec);
1233
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;
1239
1240             // Adjust both operands to be the same scale as ResScale.
1241             if (MyScale != ResScale)
1242                 x.AdjustScale(ResScale - MyScale, true);
1243
1244             if (OpScale != ResScale)
1245                 y.AdjustScale(ResScale - OpScale, true);
1246
1247             // When sign of first operand is negative
1248             // negate all operands including result.
1249             if (!fMySignPos) {
1250                 fMySignPos = !fMySignPos;
1251                 fOpSignPos = !fOpSignPos;
1252                 fResSignPos = !fResSignPos;
1253             }
1254
1255             // Initialize operand lengths and pointer.
1256             culOp1 = x.m_bLen;
1257             culOp2 = y.m_bLen;
1258
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};
1261
1262             if (fOpSignPos) {
1263                 dwlAccum = 0;
1264
1265                 // 
1266
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];
1275
1276                     rglData1[iulData] = (uint)dwlAccum; // equiv to mod x_lInt32Base
1277                     dwlAccum >>= 32; // equiv to div x_lInt32Base
1278                 }
1279
1280                 //If carry
1281                 if (dwlAccum != 0) {
1282                     SQLDebug.Check(dwlAccum < x_ulInt32Base);
1283
1284                     //Either overflowed
1285                     if (iulData == x_cNumeMax)
1286                         throw new OverflowException(SQLResource.ArithOverflowMessage);
1287
1288                     // Or extended length
1289                     rglData1[iulData] = (uint)dwlAccum;
1290                     iulData ++;
1291                 }
1292
1293                 // Set result length
1294                 bLen = (byte) iulData;
1295             }
1296             else {
1297                 int iulLastNonZero = 0; // The last nonzero UI
1298
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;
1306                     culOp1 = culOp2;
1307                     culOp2 = x.m_bLen;
1308                 }
1309
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];
1316
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
1322                 }
1323                 // Set length based on highest non-zero ULONG
1324                 bLen = (byte) (iulLastNonZero + 1);
1325             }
1326
1327             SqlDecimal ret = new SqlDecimal(rglData1, bLen, (byte)ResPrec, (byte)ResScale, fResSignPos);
1328
1329                         if (ret.FGt10_38() || ret.CalculatePrecision () > NUMERIC_MAX_PRECISION)
1330                 throw new OverflowException(SQLResource.ArithOverflowMessage);
1331
1332             if (ret.FZero())
1333                 ret.SetPositive();
1334
1335             ret.AssertValid();
1336
1337             return ret;
1338         }
1339
1340         /// <devdoc>
1341         ///    <para>[To be supplied.]</para>
1342         /// </devdoc>
1343         public static SqlDecimal operator -(SqlDecimal x, SqlDecimal y) {
1344             return x + (-y);
1345         }
1346
1347         //    MultNm()
1348         //
1349         //    Multiply two numerics.
1350         //
1351         //  Parameters:
1352         //        x    - IN Multiplier
1353         //        y    - IN Multiplicand
1354         //
1355         //    Result scale and precision(same as in SQL Server Manual and Hydra):
1356         //        scale = s1 + s2
1357         //        precison = s1 + s2 + (p1 - s1) + (p2 - s2) + 1
1358         //
1359         //    Overflow Rules:
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.
1370         //
1371         //    Algorithm:
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.
1379         //
1380         /// <devdoc>
1381         ///    <para>[To be supplied.]</para>
1382         /// </devdoc>
1383         public static SqlDecimal operator *(SqlDecimal x, SqlDecimal y) {
1384             x.AssertValid();
1385             y.AssertValid();
1386
1387             if (x.IsNull || y.IsNull)
1388                 return Null;
1389
1390             //Implementation:
1391             //        I) Figure result scale,prec
1392             //        II) Perform mult.
1393             //        III) Adjust product to result scale,prec
1394
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
1401
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
1409
1410             SqlDecimal  ret;
1411
1412
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;
1417
1418             //result precison = s1 + s2 + (p1 - s1) + (p2 - s2) + 1
1419             ResPrec = ResScale + ResInteger;
1420
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;
1426
1427             //
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.
1431             //
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));
1436
1437             lScaleAdjust = ResScale - ActualScale;
1438
1439             fResPositive = (x.IsPositive == y.IsPositive);//positive if both signs same.
1440
1441             // II) Perform multiplication
1442
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};
1445
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
1451             int         idRes = 0;
1452
1453             //Iterate over the bytes of multiplier
1454             for (iulPlier = 0; iulPlier < x.m_bLen; iulPlier++) {
1455                 ulPlier = rglData1[iulPlier];
1456                 dwlAccum = 0;
1457
1458                 //Multiply each UI4 of multiCand by ulPliear and accumulate into result buffer
1459
1460                 // Start on correct place in result
1461                 idRes = iulPlier;
1462
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
1472                     else
1473                         dwlNextAccum = 0;
1474
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
1478
1479                     // dwlNextAccum can't overflow next iteration
1480                     SQLDebug.Check(dwlAccum < x_ulInt32Base*2);
1481                 }
1482
1483                 SQLDebug.Check(dwlAccum < x_ulInt32Base); // can never final accum > 1 more UI4
1484                 if (dwlAccum != 0)
1485                     rgulRes[idRes ++] = (uint)dwlAccum;
1486             }
1487             // Skip leading 0s (may exist if we are multiplying by 0)
1488             for (;(rgulRes[idRes] == 0) && (idRes > 0); idRes--)
1489                 ;
1490             // Calculate actual result length
1491             culRes = idRes + 1;
1492
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);
1498
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
1502
1503                     uint    ulRem;          //Remainder when downshifting
1504                     uint    ulShiftBase;    //What to multiply by to effect scale adjust
1505
1506                     do {
1507                         if (lScaleAdjust <= -9) {
1508                             ulShiftBase = x_rgulShiftBase[8];
1509                             lScaleAdjust += 9;
1510                         }
1511                         else {
1512                             ulShiftBase = x_rgulShiftBase[-lScaleAdjust - 1];
1513                             lScaleAdjust = 0;
1514                         }
1515                         MpDiv1 (rgulRes, ref culRes, ulShiftBase, out ulRem);
1516                     }
1517                     while (lScaleAdjust != 0);
1518
1519                     // Still do not fit?
1520                     if (culRes > x_cNumeMax)
1521                         throw new OverflowException(SQLResource.ArithOverflowMessage);
1522
1523                     for (idRes = culRes; idRes < x_cNumeMax; idRes ++)
1524                         rgulRes[idRes] = 0;
1525                     ret = new SqlDecimal(rgulRes, (byte)culRes, (byte)ResPrec, (byte)ResScale, fResPositive);
1526
1527                     // Is it greater than 10**38?
1528                     if (ret.FGt10_38())
1529                         throw new OverflowException(SQLResource.ArithOverflowMessage);
1530
1531                     ret.AssertValid();
1532
1533                     // If remainder is 5 or above, increment/decrement by 1.
1534                     if (ulRem >= ulShiftBase/2)
1535                         ret.AddULong(1);
1536                     // After adjusting, if the result is 0 and remainder is less than 5,
1537                     // set the sign to be positive
1538                     if (ret.FZero ())
1539                         ret.SetPositive();
1540
1541                     return ret;
1542                 }
1543
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
1550
1551                 for (idRes = culRes; idRes < x_cNumeMax; idRes ++)
1552                     rgulRes[idRes] = 0;
1553                 ret = new SqlDecimal(rgulRes, (byte)culRes, (byte)ResPrec, (byte)ActualScale, fResPositive);
1554
1555                 if (ret.FZero ())
1556                     ret.SetPositive();
1557
1558                 ret.AssertValid();
1559
1560                 ret.AdjustScale(lScaleAdjust, true);
1561
1562                 return ret;
1563             }
1564             else {
1565                 if (culRes > x_cNumeMax)
1566                     throw new OverflowException(SQLResource.ArithOverflowMessage);
1567
1568                 for (idRes = culRes; idRes < x_cNumeMax; idRes ++)
1569                     rgulRes[idRes] = 0;
1570                 ret = new SqlDecimal(rgulRes, (byte)culRes, (byte)ResPrec, (byte)ResScale, fResPositive);
1571
1572                 // Is it greater than 10**38?
1573                 if (ret.FGt10_38 ())
1574                     throw new OverflowException(SQLResource.ArithOverflowMessage);
1575
1576                 if (ret.FZero ())
1577                     ret.SetPositive();
1578
1579                 ret.AssertValid();
1580
1581                 return ret;
1582             }
1583         }
1584
1585         //-----------------------------------------------------------
1586         //DivNm():
1587         //  Divide numeric by numeric.
1588         //    The Quotient will be returned in *this
1589         //
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;
1595         //
1596         //Overflow Rules:
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
1607         //
1608         //Algorithm
1609         //  Call general purpose arbitrary precision division routine with scale = 0.
1610         //    Scale,prec adjusted later.
1611         //
1612         /// <devdoc>
1613         ///    <para>[To be supplied.]</para>
1614         /// </devdoc>
1615         public static SqlDecimal operator /(SqlDecimal x, SqlDecimal y) {
1616             if (x.IsNull || y.IsNull)
1617                 return Null;
1618
1619             x.AssertValid();
1620             y.AssertValid();
1621
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
1631
1632             // Steps:
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
1636
1637             // 0) Check for Div by 0
1638             if (y.FZero())
1639                 throw new DivideByZeroException(SQLResource.DivideByZeroMessage);
1640
1641             // 1) Figure out result prec,scale,sign..
1642             fResSignPos = (x.IsPositive == y.IsPositive);//sign of result
1643
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;
1648             bPrecD = x.m_bPrec;
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);
1653
1654             ResInteger = Math.Min(ResInteger, NUMERIC_MAX_PRECISION);
1655             ResPrec = ResInteger + ResScale;
1656
1657             if (ResPrec >  NUMERIC_MAX_PRECISION)
1658                 ResPrec = NUMERIC_MAX_PRECISION;
1659
1660             // If overflow, reduce the scale to avoid truncation of data
1661             ResScale = Math.Min((ResPrec - ResInteger), ResScale);
1662             ResScale = Math.Max(ResScale, MinScale);
1663
1664             //Adjust the scale of the dividend
1665             lScaleAdjust = ResScale - (int)x.m_bScale + (int)y.m_bScale;
1666             x.AdjustScale(lScaleAdjust, true);
1667
1668             // Step2: Actual Computation
1669
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};
1672
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
1677             int culQ, culR;
1678
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);
1682
1683             // Construct the result from Q
1684             ZeroToMaxLen (rgulQ, culQ);
1685             SqlDecimal ret = new SqlDecimal(rgulQ, (byte)culQ, (byte)ResPrec, (byte)ResScale, fResSignPos);
1686
1687             if (ret.FZero())
1688                 ret.SetPositive();
1689
1690             ret.AssertValid();
1691
1692             return ret;
1693         }
1694
1695
1696
1697         // Implicit conversions
1698
1699         // Implicit conversion from SqlBoolean to SqlDecimal
1700         /// <devdoc>
1701         ///    <para>[To be supplied.]</para>
1702         /// </devdoc>
1703         public static explicit operator SqlDecimal(SqlBoolean x) {
1704             return x.IsNull ? Null : new SqlDecimal((int)x.ByteValue);
1705         }
1706
1707         // Implicit conversion from SqlByte to SqlDecimal
1708         /// <devdoc>
1709         ///    <para>[To be supplied.]</para>
1710         /// </devdoc>
1711         public static implicit operator SqlDecimal(SqlByte x) {
1712             return x.IsNull ? Null : new SqlDecimal((int)(x.Value));
1713         }
1714
1715         // Implicit conversion from SqlInt16 to SqlDecimal
1716         /// <devdoc>
1717         ///    <para>[To be supplied.]</para>
1718         /// </devdoc>
1719         public static implicit operator SqlDecimal(SqlInt16 x) {
1720             return x.IsNull ? Null : new SqlDecimal((int)(x.Value));
1721         }
1722
1723         // Implicit conversion from SqlInt32 to SqlDecimal
1724         /// <devdoc>
1725         ///    <para>[To be supplied.]</para>
1726         /// </devdoc>
1727         public static implicit operator SqlDecimal(SqlInt32 x) {
1728             return x.IsNull ? Null : new SqlDecimal(x.Value);
1729         }
1730
1731         // Implicit conversion from SqlInt64 to SqlDecimal
1732         /// <devdoc>
1733         ///    <para>[To be supplied.]</para>
1734         /// </devdoc>
1735         public static implicit operator SqlDecimal(SqlInt64 x) {
1736             return x.IsNull ? Null : new SqlDecimal(x.Value);
1737         }
1738
1739         // Implicit conversion from SqlMoney to SqlDecimal
1740         /// <devdoc>
1741         ///    <para>[To be supplied.]</para>
1742         /// </devdoc>
1743         public static implicit operator SqlDecimal(SqlMoney x) {
1744             return x.IsNull ? Null : new SqlDecimal(x.ToDecimal());
1745         }
1746
1747
1748         // Explicit conversions
1749
1750          // Explicit conversion from SqlSingle to SqlDecimal
1751         /// <devdoc>
1752         ///    <para>[To be supplied.]</para>
1753         /// </devdoc>
1754         public static explicit operator SqlDecimal(SqlSingle x) {
1755             return x.IsNull ? SqlDecimal.Null : new SqlDecimal((double)(x.Value));
1756         }
1757
1758        // Explicit conversion from SqlDouble to SqlDecimal
1759         /// <devdoc>
1760         ///    <para>[To be supplied.]</para>
1761         /// </devdoc>
1762         public static explicit operator SqlDecimal(SqlDouble x) {
1763             return x.IsNull ? SqlDecimal.Null : new SqlDecimal(x.Value);
1764         }
1765
1766         // Explicit conversion from SqlString to SqlDecimal
1767         // Throws FormatException or OverflowException if necessary.
1768         /// <devdoc>
1769         ///    <para>[To be supplied.]</para>
1770         /// </devdoc>
1771         public static explicit operator SqlDecimal(SqlString x) {
1772             return x.IsNull ? Null : SqlDecimal.Parse(x.Value);
1773         }
1774
1775         // private methods
1776
1777         //----------------------------------------------------------------------
1778         // Is this RE numeric valid?
1779         [System.Diagnostics.Conditional("DEBUG")]
1780         private void AssertValid() {
1781             if (IsNull)
1782                 return;
1783
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");
1789
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");
1792
1793             uint[] rglData = new uint[4] {m_data1, m_data2, m_data3, m_data4};
1794
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");
1798             }
1799
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");
1803         }
1804 /*
1805         // print the data members
1806         [System.Diagnostics.Conditional("DEBUG")]
1807         private void Print() {
1808             if (IsNull) {
1809                 Debug.WriteLine("Numeric: Null");
1810                 return;
1811             }
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());
1816         }
1817
1818         [System.Diagnostics.Conditional("DEBUG")]
1819         private void Print(String s) {
1820             Debug.WriteLine("*** " + s + " ***");
1821             if (IsNull) {
1822                 Debug.WriteLine("Numeric: Null");
1823                 return;
1824             }
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());
1829         }
1830 */
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");
1834
1835             switch (cUI4sCur) {
1836                 case 1:
1837                     rgulData[1] = rgulData[2] = rgulData[3] = 0;
1838                     break;
1839
1840                 case 2:
1841                     rgulData[2] = rgulData[3] = 0;
1842                     break;
1843
1844                 case 3:
1845                     rgulData[3] = 0;
1846                     break;
1847             }
1848         }
1849
1850         // Set all extra uints to zero
1851         /*
1852         private void ZeroToMaxLen(int cUI4sCur) {
1853             switch (cUI4sCur) {
1854                 case 1:
1855                     m_data2 = m_data3 = m_data4 = x_uiZero;
1856                     break;
1857
1858                 case 2:
1859                     m_data3 = m_data4 = x_uiZero;
1860                     break;
1861
1862                 case 3:
1863                     m_data4 = x_uiZero;
1864                     break;
1865             }
1866         }
1867         */
1868
1869         //Determine the number of uints needed for a numeric given a precision
1870         //Precision        Length
1871         //    0            invalid
1872         //    1-9            1
1873         //    10-19        2
1874         //    20-28        3
1875         //    29-38        4
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};
1881
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];
1886         }
1887
1888         // check whether is zero
1889         private bool FZero() {
1890             return(m_data1 == 0) && (m_bLen <= 1);
1891         }
1892
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));
1898         }
1899
1900         private bool FGt10_38(uint[] rglData) {
1901             SQLDebug.Check(rglData.Length == 4, "rglData.Length == 4", "Wrong array length: " + rglData.Length.ToString(CultureInfo.InvariantCulture));
1902
1903             return    rglData[3] >= 0x4b3b4ca8L &&
1904             ((rglData[3] > 0x4b3b4ca8L) || (rglData[2] > 0x5a86c47aL) ||
1905              (rglData[2] == 0x5a86c47aL) && (rglData[1] >= 0x098a2240L));
1906         }
1907
1908
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;
1929
1930         //------------------------------------------------------------------
1931         //BGetPrecI4
1932         //    Return the precision(number of significant digits) of a integer
1933         private static byte BGetPrecUI4(uint value) {
1934             int ret;
1935
1936             // Now do the (almost) binary search
1937             if (value < x_ulT4) {
1938                 if (value < x_ulT2)
1939                     ret = value >= x_ulT1 ? 2 : 1;
1940                 else
1941                     ret = value >= x_ulT3 ? 4 : 3;
1942             }
1943             else if (value < x_ulT8) {
1944                 if (value < x_ulT6)
1945                     ret = value >= x_ulT5 ? 6 : 5;
1946                 else
1947                     ret = value >= x_ulT7 ? 8 : 7;
1948             }
1949             else
1950                 ret = value >= x_ulT9 ? 10 : 9;
1951
1952             return(byte)ret;
1953         }
1954
1955         //------------------------------------------------------------------
1956         //BGetPrecI8
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);
1961         }
1962
1963         private static byte  BGetPrecUI8(ulong dwlVal) {
1964             int ret;
1965
1966             // Now do the (almost) binary search
1967             if (dwlVal < x_ulT8) {
1968                 uint ulVal = (uint) dwlVal;
1969
1970                 if (ulVal < x_ulT4) {
1971                     if (ulVal < x_ulT2)
1972                         ret = (ulVal >= x_ulT1) ? 2 : 1;
1973                     else
1974                         ret = (ulVal >= x_ulT3) ? 4 : 3;
1975                 }
1976                 else {
1977                     if (ulVal < x_ulT6)
1978                         ret = (ulVal >= x_ulT5) ? 6 : 5;
1979                     else
1980                         ret = (ulVal >= x_ulT7) ? 8 : 7;
1981                 }
1982             }
1983             else if (dwlVal < x_dwlT16) {
1984                 if (dwlVal < x_dwlT12) {
1985                     if (dwlVal < x_dwlT10)
1986                         ret = (dwlVal >= x_ulT9) ? 10 : 9;
1987                     else
1988                         ret = (dwlVal >= x_dwlT11) ? 12 : 11;
1989                 }
1990                 else {
1991                     if (dwlVal < x_dwlT14)
1992                         ret = (dwlVal >= x_dwlT13) ? 14 : 13;
1993                     else
1994                         ret = (dwlVal >= x_dwlT15) ? 16 : 15;
1995                 }
1996             }
1997             else {
1998                 if (dwlVal < x_dwlT18)
1999                     ret = (dwlVal >= x_dwlT17) ? 18 : 17;
2000                 else
2001                     ret = (dwlVal >= x_dwlT19) ? 20 : 19;
2002             }
2003
2004             return(byte)ret;
2005         }
2006
2007 #if DEBUG
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
2010
2011         //
2012         //    BActualPrec()
2013         //
2014         //    Determine the actual number of significant digits (precision) of a numeric
2015         //
2016         //    Parameters:
2017         //
2018         //    Complexity:
2019         //        For small numerics, use simpler routines = O(n)
2020         //        Else, max 3 divisions of mp by ULONG, then again simpler routine.
2021         //
2022         //    Returns:
2023         //        a byte containing the actual precision
2024         //
2025         private byte BActualPrec () {
2026             if (m_bPrec == 0 || m_bLen < 1)
2027                 return 0;
2028
2029             int     ciulU = m_bLen;
2030             int     Prec;
2031             uint    ulRem;
2032
2033             if (ciulU == 1) {
2034                 Prec = BGetPrecUI4 (m_data1);
2035             }
2036             else if (ciulU == 2) {
2037                 Prec = BGetPrecUI8 (m_data1, m_data2);
2038             }
2039             else {
2040                 uint[]  rgulU = new uint[4] { m_data1, m_data2, m_data3, m_data4};
2041                 Prec = 0;
2042                 do {
2043                     MpDiv1 (rgulU, ref ciulU, 1000000000, out ulRem);
2044                     Prec += 9;
2045                 }
2046                 while (ciulU > 2);
2047                 SQLDebug.Check (Prec == 9 || Prec == 18 || Prec == 27);
2048                 Prec += BGetPrecUI8 (rgulU[0], rgulU[1]);
2049             }
2050
2051             // If number of significant digits less than scale, return scale
2052             return(Prec < m_bScale ? m_bScale : (byte)Prec);
2053         }
2054 #endif
2055
2056         //    AddULong()
2057         //
2058         //    Add ulAdd to this numeric.  The result will be returned in *this.
2059         //
2060         //    Parameters:
2061         //        this    - IN Operand1 & OUT Result
2062         //        ulAdd    - IN operand2.
2063         //
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
2068
2069             uint[] rguiData = new uint[4] { m_data1, m_data2, m_data3, m_data4};
2070
2071             // Add, starting at the LS UI4 until out of UI4s or no carry
2072             iData = 0;
2073             do {
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);
2079                     return;
2080                 }
2081                 iData ++;
2082             }
2083             while (iData < iDataMax);
2084
2085             // There is carry at the end
2086
2087             SQLDebug.Check(dwlAccum < x_ulInt32Base, "dwlAccum < x_lInt32Base", "");
2088
2089             // Either overflowed
2090             if (iData == x_cNumeMax)
2091                 throw new OverflowException(SQLResource.ArithOverflowMessage);
2092
2093             // Or need to extend length by 1 UI4
2094             rguiData[iData] = (uint)dwlAccum;
2095             m_bLen ++;
2096
2097             if (FGt10_38 (rguiData))
2098                 throw new OverflowException(SQLResource.ArithOverflowMessage);
2099
2100             StoreFromWorkingArray(rguiData);
2101         }
2102
2103         // multiply by a long integer
2104         private void MultByULong(uint uiMultiplier) {
2105             int     iDataMax = m_bLen; // How many UI4s currently in *this
2106
2107             ulong   dwlAccum = 0;       // accumulated sum
2108             ulong   dwlNextAccum = 0;   // accumulation past dwlAccum
2109             int     iData;              // which UI4 in *This we are on.
2110
2111             uint[] rguiData = new uint[4] { m_data1, m_data2, m_data3, m_data4};
2112
2113             for (iData = 0; iData < iDataMax; iData++) {
2114                 SQLDebug.Check(dwlAccum < x_ulInt32Base);
2115
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
2121                 else
2122                     dwlNextAccum = 0;
2123                 rguiData[iData] = (uint)dwlAccum;           // equivalent to mod x_dwlBaseUI4
2124                 dwlAccum = (dwlAccum >> 32) + dwlNextAccum; // equivalent to div x_dwlBaseUI4
2125             }
2126
2127             // If any carry,
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);
2133
2134                 // Or extend length by one uint
2135                 rguiData[iDataMax] = (uint)dwlAccum;
2136                 m_bLen ++;
2137             }
2138
2139             if (FGt10_38 (rguiData))
2140                 throw new OverflowException(SQLResource.ArithOverflowMessage);
2141
2142             StoreFromWorkingArray(rguiData);
2143         }
2144
2145
2146         //    DivByULong()
2147         //
2148         //    Divide numeric value by a ULONG.  The result will be returned
2149         //    in the dividend *this.
2150         //
2151         //    Parameters:
2152         //        this        - IN Dividend & OUT Result
2153         //        ulDivisor    - IN Divisor
2154         //    Returns:        - OUT Remainder
2155         //
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
2162
2163             // Check for zero divisor.
2164             if (dwlDivisor == 0)
2165                 throw new DivideByZeroException(SQLResource.DivideByZeroMessage);
2166
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};
2169
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
2178             //                                    rglData < 2^32
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;
2188
2189                 // While current part of quotient still 0, reduce length
2190                 if (fAllZero && (ulQuotientCur == 0)) {
2191                     m_bLen --;
2192                 } else {
2193                     fAllZero = false;
2194                 }
2195             }
2196
2197             StoreFromWorkingArray(rguiData);
2198
2199             // If result is 0, preserve sign but set length to 5
2200             if (fAllZero)
2201                 m_bLen = 1;
2202
2203             AssertValid();
2204
2205             // return the remainder
2206             SQLDebug.Check(dwlAccum < x_ulInt32Base);
2207             return(uint)dwlAccum;
2208         }
2209
2210         //    AdjustScale()
2211         //
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.
2217         //
2218         internal void AdjustScale(int digits, bool fRound) {
2219             SQLDebug.Check(!IsNull, "!IsNull", "In AdjustScale");
2220
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;
2226
2227             //If downshifting causes truncation of data
2228             if (lAdjust + m_bScale < 0)
2229                 throw new SqlTruncateException();
2230
2231             //If uphifting causes scale overflow
2232             if (lAdjust + m_bScale > NUMERIC_MAX_PRECISION)
2233                 throw new OverflowException(SQLResource.ArithOverflowMessage);
2234
2235             bNewScale = (byte) (lAdjust + m_bScale);
2236             bNewPrec = (byte) (Math.Min(NUMERIC_MAX_PRECISION,Math.Max(1,lAdjust + m_bPrec)));
2237
2238             if (lAdjust > 0) {
2239                 m_bScale = bNewScale;
2240                 m_bPrec  = bNewPrec;
2241
2242                 while (lAdjust > 0) {
2243                     //if lAdjust>=9, downshift by 10^9 each time, otherwise by the full amount
2244                     if (lAdjust >= 9) {
2245                         ulShiftBase = x_rgulShiftBase[8];
2246                         lAdjust -= 9;
2247                     }
2248                     else {
2249                         ulShiftBase = x_rgulShiftBase[lAdjust-1];
2250                         lAdjust = 0;
2251                     }
2252                     MultByULong(ulShiftBase);
2253                 }
2254             }
2255             else if (lAdjust < 0) {
2256                 do {
2257                     if (lAdjust <= -9) {
2258                         ulShiftBase = x_rgulShiftBase[8];
2259                         lAdjust += 9;
2260                     }
2261                     else {
2262                         ulShiftBase = x_rgulShiftBase[-lAdjust - 1];
2263                         lAdjust = 0;
2264                     }
2265                     ulRem = DivByULong (ulShiftBase);
2266                 }
2267                 while (lAdjust < 0);
2268
2269                 // Do we really need to round?
2270                 fNeedRound = (ulRem >= ulShiftBase/2);
2271
2272                 m_bScale = bNewScale;
2273                 m_bPrec =  bNewPrec;
2274             }
2275
2276             AssertValid();
2277
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.
2282                 AddULong(1);
2283             }
2284             else if (FZero())
2285                 SetPositive();
2286         }
2287
2288         // Adjust scale of a SqlDecimal
2289         /// <devdoc>
2290         ///    <para>[To be supplied.]</para>
2291         /// </devdoc>
2292         public static SqlDecimal AdjustScale(SqlDecimal n, int digits, bool fRound) {
2293             if (n.IsNull)
2294                 return SqlDecimal.Null;
2295
2296             SqlDecimal ret = n;
2297             ret.AdjustScale(digits, fRound);
2298             return ret;
2299         }
2300
2301         // Convert to a specific precision and scale
2302         /// <devdoc>
2303         ///    <para>[To be supplied.]</para>
2304         /// </devdoc>
2305         public static SqlDecimal ConvertToPrecScale(SqlDecimal n, int precision, int scale) {
2306             CheckValidPrecScale(precision, scale);
2307             n.AssertValid();
2308
2309             if (n.IsNull)
2310                 return SqlDecimal.Null;
2311
2312             SqlDecimal ret = n;
2313
2314             int lPrecAdjust = precision - (int)ret.m_bPrec;//Adjustment to precision
2315             int lScaleAdjust = scale - (int)ret.m_bScale;//Adjustment to scale
2316
2317             //Adjust scale
2318             ret.AdjustScale(lScaleAdjust, true);
2319
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
2323             //of cases
2324
2325             //The number of bytes storage required by the new precision
2326             byte cbWithNewPrec = CLenFromPrec((byte)precision);
2327
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();
2332             }
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();
2337             }
2338
2339             //Adjust precision
2340             ret.m_bPrec = (byte)precision;
2341
2342             ret.AssertValid();
2343
2344             return ret;
2345         }
2346
2347         //    LAbsCmp()
2348         //
2349         //    Compare the absolute value of two numerics without checking scale
2350         //
2351         //  Parameters:
2352         //        this    - IN Operand1
2353         //        snumOp    - IN Operand2
2354         //
2355         //    Returns:
2356         //        positive    - |this| > |snumOp|
2357         //        0            - |this| = |snumOp|
2358         //        negative    - |this| < |snumOp|
2359         //
2360         private int LAbsCmp(SqlDecimal snumOp) {
2361
2362             int         iData;  //which UI4 we are operating on
2363             int         culOp;  //#of UI4s on operand
2364             int         culThis; //# of UI4s in this
2365
2366             // If one longer, it is larger
2367             culOp = snumOp.m_bLen;
2368             culThis = m_bLen;
2369             if (culOp != culThis)
2370                 return(culThis > culOp) ? 1 : -1;
2371
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};
2374
2375             // Loop through numeric value checking each byte for differences.
2376             iData = culOp-1;
2377             do {
2378                 // 
2379
2380                 if (rglData1[iData] != rglData2[iData])
2381                     return((rglData1[iData] > rglData2[iData]) ? 1 : -1);
2382                 iData --;
2383             }
2384             while (iData >= 0);
2385
2386             // All UI4s the same, return 0.
2387             return 0;
2388         }
2389
2390         // Move multi-precision number
2391         private static void MpMove
2392         (
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
2397         ) {
2398             ciulD = ciulS;
2399
2400             SQLDebug.Check(rgulS.Length >= ciulS, "rgulS.Length >= ciulS", "Invalid array length");
2401             SQLDebug.Check(rgulD.Length >= ciulS, "rgulD.Length >= ciulS", "Invalid array length");
2402
2403             for (int i = 0; i < ciulS; i ++)
2404                 rgulD[i] = rgulS[i];
2405         }
2406
2407         // Set multi-precision number to one super-digit
2408         private static void MpSet
2409         (
2410         uint[]  rgulD,      // Out    | Number
2411         out int ciulD,      // Out    | # of digits in D
2412         uint    iulN        // In    | ULONG to set
2413         ) {
2414             ciulD = 1;
2415             rgulD[0] = iulN;
2416         }
2417
2418         // Normalize multi-precision number - remove leading zeroes
2419         private static void MpNormalize
2420         (
2421         uint[]  rgulU,      // In   | Number
2422         ref int ciulU       // InOut| # of digits
2423         ) {
2424             while (ciulU > 1 && rgulU[ciulU-1] == 0)
2425                 ciulU --;
2426         }
2427
2428         // Multi-precision one super-digit multiply in place.
2429         // D = D * X
2430         // Length can increase
2431         private static void MpMul1
2432         (
2433         uint[]  piulD,      // InOut| D
2434         ref int ciulD,      // InOut| # of digits in D
2435         uint    iulX        // In    | X
2436         ) {
2437             SQLDebug.Check(iulX > x_uiZero);
2438             uint ulCarry = 0;
2439             int iData;
2440             ulong dwlAccum;
2441
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);
2447             }
2448
2449             // If overflow occurs, increase precision
2450             if (ulCarry != 0) {
2451                 piulD[iData] = ulCarry;
2452                 ciulD ++;
2453             }
2454         }
2455
2456         // Multi-precision one super-digit divide in place.
2457         // U = U / D,
2458         // R = U % D
2459         // Length of U can decrease
2460         private static void MpDiv1
2461         (
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
2466         ) {
2467             SQLDebug.Check(rgulU.Length == x_cNumeMax);
2468
2469             uint    ulCarry = 0;
2470             ulong   dwlAccum;
2471             ulong   ulD = (ulong)iulD;
2472             int     idU = ciulU;
2473
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");
2477
2478             while (idU > 0) {
2479                 idU --;
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)
2483             }
2484             iulR = ulCarry;
2485             MpNormalize (rgulU, ref ciulU);
2486         }
2487
2488         internal static ulong DWL(uint lo, uint hi) {
2489             return(ulong)lo + ( ((ulong)hi) << 32 );
2490         }
2491
2492         private static uint HI(ulong x) {
2493             return(uint)(x >> 32);
2494         }
2495
2496         private static uint LO(ulong x) {
2497             return(uint)x;
2498         }
2499
2500         // Multi-precision divide.
2501         // Q = U / D,
2502         // R = U % D,
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.
2507
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).
2516         //
2517         private static void MpDiv
2518         (
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
2527         ) {
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);
2532
2533             // Division by zero?
2534             if (ciulD == 1 && rgulD[0] == 0) {
2535                 ciulQ = ciulR = 0;
2536             }
2537
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]);
2542             }
2543
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
2548             }
2549
2550             // Try to divide faster - check for remaining good sizes (8 / 4, 8 / 8)
2551             else if (ciulU <= 2) {
2552                 ulong dwlU, dwlD, dwlT;
2553
2554                 dwlU = DWL (rgulU[0], rgulU[1]);
2555                 dwlD = rgulD[0];
2556                 if (ciulD > 1)
2557                     dwlD += ( ((ulong)rgulD[1]) << 32 );
2558                 dwlT = dwlU / dwlD;
2559                 rgulQ[0] = LO (dwlT);
2560                 rgulQ[1] = HI (dwlT);
2561                 ciulQ = (HI (dwlT) != 0) ? 2 : 1;
2562                 dwlT = dwlU % dwlD;
2563                 rgulR[0] = LO (dwlT);
2564                 rgulR[1] = HI (dwlT);
2565                 ciulR = (HI (dwlT) != 0) ? 2 : 1;
2566             }
2567
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
2571                 uint remainder;
2572                 MpDiv1 (rgulQ, ref ciulQ, rgulD[0], out remainder);     // Q = Q / D, R = Q % D
2573                 rgulR[0] = remainder;
2574                 ciulR = 1;
2575             }
2576
2577             // Worst case. Knuth, "The Art of Computer Programming", 3rd edition, vol.II, Alg.D, pg 272
2578             else {
2579                 ciulQ = ciulR = 0;
2580
2581                 uint D1, ulDHigh, ulDSecond;
2582                 int iulRindex;
2583
2584                 if (rgulU != rgulR)
2585                     MpMove (rgulU, ciulU, rgulR, out ciulR);        // R = U
2586
2587                 ciulQ = ciulU - ciulD + 1;
2588                 ulDHigh = rgulD[ciulD-1];
2589
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
2592                 rgulR[ciulU] = 0;
2593                 iulRindex = ciulU;
2594                 D1 = (uint)(x_ulInt32Base / ((ulong)ulDHigh + 1));
2595                 if (D1 > 1) {
2596                     MpMul1 (rgulD, ref ciulD, D1);
2597                     ulDHigh = rgulD[ciulD-1];
2598                     MpMul1 (rgulR, ref ciulR, D1);
2599                 }
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"
2603                 do {
2604                     uint QH, RH;
2605                     int iulDindex, iulRwork;
2606                     ulong dwlAccum, dwlMulAccum;
2607
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);
2612                     else
2613                         QH = (uint)(dwlAccum / ulDHigh);
2614                     ulong ulTemp = (ulong)QH;
2615                     RH = (uint)(dwlAccum - ulTemp * (ulong)ulDHigh);
2616
2617                     while (ulDSecond * ulTemp > DWL (rgulR[iulRindex-2], RH)) {
2618                         QH --;
2619                         if (RH >= (uint) - ((int) ulDHigh))
2620                             break;
2621                         RH += ulDHigh;
2622                         ulTemp = (ulong)QH;
2623                     }
2624
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;
2634                     }
2635                     dwlAccum += (ulong)rgulR[iulRwork] - dwlMulAccum;
2636                     rgulR[iulRwork] = LO (dwlAccum);
2637                     rgulQ[iulRindex-ciulD] = QH;
2638
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
2642                         uint ulCarry;
2643
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);
2650                         }
2651                         rgulR[iulRwork] += ulCarry;
2652                     }
2653                     // D7. Loop on iulRindex
2654                     iulRindex --;
2655                 }
2656                 while (iulRindex >= ciulD);
2657                 // Normalize results
2658                 MpNormalize (rgulQ, ref ciulQ);
2659                 ciulR = ciulD;
2660                 MpNormalize (rgulR, ref ciulR);
2661                 // D8. Unnormalize: Divide D and R to get result
2662                 if (D1 > 1) {
2663                     uint ret;
2664                     MpDiv1 (rgulD, ref ciulD, D1, out ret);
2665                     MpDiv1 (rgulR, ref ciulR, D1, out ret);
2666                 }
2667             }
2668         }
2669
2670         //    CmpCompareNm()
2671         //
2672         //    Compare the value of two numerics
2673         //
2674         //    Complexity: O(pn) p: precision  n: length
2675         //
2676         //  Parameters:
2677         //        this    - IN Operand1
2678         //        snumOp    - IN operand2
2679         //
2680         //    Returns:
2681         //        EComparison.LT    - this < snumOp
2682         //        EComparison.EQ        - this = snumOp
2683         //        EComparison.GT    - this > snumOp
2684         //
2685         private EComparison CompareNm
2686         (
2687         SqlDecimal snumOp
2688         ) {
2689             AssertValid();
2690             snumOp.AssertValid();
2691
2692             //Signs of the two numeric operands
2693             int     Sign1;
2694             int     Sign2;
2695
2696             int     iFinalResult;   //Final result of comparision: positive = greater
2697                                     //than, 0 = equal, negative = less than
2698
2699             //Initialize the sign values to be 1(positive) or -1(negative)
2700             Sign1 = IsPositive ? 1 : -1;
2701             Sign2 = snumOp.IsPositive ? 1 : -1;
2702
2703             if (Sign1 != Sign2) //If different sign, the positive one is greater
2704                 return Sign1 == 1 ? EComparison.GT : EComparison.LT;
2705
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
2709                 int         ScaleDiff;
2710                 SqlDecimal  snumArg1 = this;
2711                 SqlDecimal  snumArg2 = snumOp;
2712
2713                 //First make the two operands the same scale if necessary
2714                 ScaleDiff = ((int) m_bScale) - ((int) snumOp.m_bScale);
2715
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.
2719                     try {
2720                         snumArg1.AdjustScale(-ScaleDiff, true);
2721                     }
2722                     catch (OverflowException) {
2723                         return(Sign1 > 0) ? EComparison.GT : EComparison.LT;
2724                     }
2725                 }
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.
2729                     try {
2730                         snumArg2.AdjustScale(ScaleDiff, true);
2731                     }
2732                     catch (OverflowException) {
2733                         return(Sign1 > 0) ? EComparison.LT : EComparison.GT;
2734                     }
2735                 }
2736
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);
2741                 if (0 == lResult)
2742                     return EComparison.EQ;
2743
2744                 //if both positive, result same as result from LAbsCmp;
2745                 //if both negative, result reverse of result from LAbsCmp
2746                 iFinalResult = Sign1 * lResult;
2747
2748                 if (iFinalResult < 0)
2749                     return EComparison.LT;
2750                 else
2751                     return EComparison.GT;
2752             }
2753         }
2754
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);
2758         }
2759
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);
2763         }
2764
2765         // Overloading comparison operators
2766         /// <devdoc>
2767         ///    <para>[To be supplied.]</para>
2768         /// </devdoc>
2769         public static SqlBoolean operator==(SqlDecimal x, SqlDecimal y) {
2770             return(x.IsNull || y.IsNull) ? SqlBoolean.Null : new SqlBoolean(x.CompareNm(y) == EComparison.EQ);
2771         }
2772
2773         /// <devdoc>
2774         ///    <para>[To be supplied.]</para>
2775         /// </devdoc>
2776         public static SqlBoolean operator!=(SqlDecimal x, SqlDecimal y) {
2777             return ! (x == y);
2778         }
2779
2780         /// <devdoc>
2781         ///    <para>[To be supplied.]</para>
2782         /// </devdoc>
2783         public static SqlBoolean operator<(SqlDecimal x, SqlDecimal y) {
2784             return(x.IsNull || y.IsNull) ? SqlBoolean.Null : new SqlBoolean(x.CompareNm(y) == EComparison.LT);
2785         }
2786
2787         /// <devdoc>
2788         ///    <para>[To be supplied.]</para>
2789         /// </devdoc>
2790         public static SqlBoolean operator>(SqlDecimal x, SqlDecimal y) {
2791             return(x.IsNull || y.IsNull) ? SqlBoolean.Null : new SqlBoolean(x.CompareNm(y) == EComparison.GT);
2792         }
2793
2794         /// <devdoc>
2795         ///    <para>[To be supplied.]</para>
2796         /// </devdoc>
2797         public static SqlBoolean operator<=(SqlDecimal x, SqlDecimal y) {
2798             if (x.IsNull || y.IsNull)
2799                 return SqlBoolean.Null;
2800             else {
2801                 EComparison result = x.CompareNm(y);
2802                 return new SqlBoolean(result == EComparison.LT || result == EComparison.EQ);
2803             }
2804         }
2805
2806         /// <devdoc>
2807         ///    <para>[To be supplied.]</para>
2808         /// </devdoc>
2809         public static SqlBoolean operator>=(SqlDecimal x, SqlDecimal y) {
2810             if (x.IsNull || y.IsNull)
2811                 return SqlBoolean.Null;
2812             else {
2813                 EComparison result = x.CompareNm(y);
2814                 return new SqlBoolean(result == EComparison.GT || result == EComparison.EQ);
2815             }
2816         }
2817
2818
2819         //--------------------------------------------------
2820         // Alternative methods for overloaded operators
2821         //--------------------------------------------------
2822
2823         // Alternative method for operator +
2824         public static SqlDecimal Add(SqlDecimal x, SqlDecimal y) {
2825             return x + y;
2826         }
2827         // Alternative method for operator -
2828         public static SqlDecimal Subtract(SqlDecimal x, SqlDecimal y) {
2829             return x - y;
2830         }
2831
2832         // Alternative method for operator *
2833         public static SqlDecimal Multiply(SqlDecimal x, SqlDecimal y) {
2834             return x * y;
2835         }
2836
2837         // Alternative method for operator /
2838         public static SqlDecimal Divide(SqlDecimal x, SqlDecimal y) {
2839             return x / y;
2840         }
2841
2842         // Alternative method for operator ==
2843         public static SqlBoolean Equals(SqlDecimal x, SqlDecimal y) {
2844             return (x == y);
2845         }
2846
2847         // Alternative method for operator !=
2848         public static SqlBoolean NotEquals(SqlDecimal x, SqlDecimal y) {
2849             return (x != y);
2850         }
2851
2852         // Alternative method for operator <
2853         public static SqlBoolean LessThan(SqlDecimal x, SqlDecimal y) {
2854             return (x < y);
2855         }
2856
2857         // Alternative method for operator >
2858         public static SqlBoolean GreaterThan(SqlDecimal x, SqlDecimal y) {
2859             return (x > y);
2860         }
2861
2862         // Alternative method for operator <=
2863         public static SqlBoolean LessThanOrEqual(SqlDecimal x, SqlDecimal y) {
2864             return (x <= y);
2865         }
2866
2867         // Alternative method for operator >=
2868         public static SqlBoolean GreaterThanOrEqual(SqlDecimal x, SqlDecimal y) {
2869             return (x >= y);
2870         }
2871
2872         // Alternative method for conversions.
2873
2874         public SqlBoolean ToSqlBoolean() {
2875             return (SqlBoolean)this;
2876         }
2877
2878         public SqlByte ToSqlByte() {
2879             return (SqlByte)this;
2880         }
2881
2882         public SqlDouble ToSqlDouble() {
2883             return (SqlDouble)this;
2884         }
2885
2886         public SqlInt16 ToSqlInt16() {
2887             return (SqlInt16)this;
2888         }
2889
2890         public SqlInt32 ToSqlInt32() {
2891             return (SqlInt32)this;
2892         }
2893
2894         public SqlInt64 ToSqlInt64() {
2895             return (SqlInt64)this;
2896         }
2897
2898         public SqlMoney ToSqlMoney() {
2899             return (SqlMoney)this;
2900         }
2901
2902         public SqlSingle ToSqlSingle() {
2903             return (SqlSingle)this;
2904         }
2905
2906         public SqlString ToSqlString() {
2907             return (SqlString)this;
2908         }
2909
2910         private static char ChFromDigit(uint uiDigit) {
2911             SQLDebug.Check(uiDigit < 10);
2912             return(char)(uiDigit + '0');
2913         }
2914
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];
2922         }
2923
2924         private void SetToZero() {
2925             SQLDebug.Check(m_bPrec >= 1);
2926             m_bLen = 1;
2927             m_data1 =
2928             m_data2 =
2929             m_data3 =
2930             m_data4 = 0;
2931             m_bStatus = (byte) (x_bNotNull | x_bPositive);
2932             AssertValid();
2933         }
2934
2935         // Truncate to integer
2936         private void MakeInteger(out bool fFraction) {
2937             uint ulRem;
2938             int iAdjust = m_bScale;
2939
2940             fFraction = false;
2941
2942             while (iAdjust > 0) {
2943                 if (iAdjust >= 9) {
2944                     ulRem = DivByULong (x_rgulShiftBase[8]);
2945                     iAdjust -= 9;
2946                 }
2947                 else {
2948                     ulRem = DivByULong (x_rgulShiftBase[iAdjust-1]);
2949                     iAdjust = 0;
2950                 }
2951
2952                 // Check for remainder and set fFraction flag.
2953                 if (ulRem != 0)
2954                     fFraction = true;
2955             }
2956
2957             m_bScale = 0;
2958             AssertValid();
2959         }
2960
2961         // Builtin functions
2962
2963         // Abs - absolute value
2964         /// <devdoc>
2965         ///    <para>[To be supplied.]</para>
2966         /// </devdoc>
2967         public static SqlDecimal Abs(SqlDecimal n) {
2968             n.AssertValid();
2969
2970             if (n.IsNull)
2971                 return SqlDecimal.Null;
2972
2973             n.SetPositive();
2974             n.AssertValid();
2975             return n;
2976         }
2977
2978         // Ceiling - next smallest integer greater than or equal to the numeric
2979         /// <devdoc>
2980         ///    <para>[To be supplied.]</para>
2981         /// </devdoc>
2982         public static SqlDecimal Ceiling(SqlDecimal n) {
2983             n.AssertValid();
2984
2985             if (n.IsNull)
2986                 return SqlDecimal.Null;
2987
2988             if (n.m_bScale == 0)
2989                 return n;
2990
2991             bool fFraction;    //Fractional flag
2992
2993             n.MakeInteger(out fFraction);
2994
2995             //When the numeric has fraction and is positive, adjust by adding 1.
2996             //Otherwise return the integral part.
2997             if (fFraction && n.IsPositive) {
2998                 n.AddULong(1);
2999             }
3000
3001             if (n.FZero())//if result is zero, sign should be positive
3002                 n.SetPositive();
3003             n.AssertValid();
3004             return n;
3005         }
3006
3007         // Floor - next largest integer smaller or equal to the numeric
3008         /// <devdoc>
3009         ///    <para>[To be supplied.]</para>
3010         /// </devdoc>
3011         public static SqlDecimal Floor(SqlDecimal n) {
3012             n.AssertValid();
3013
3014             if (n.IsNull)
3015                 return SqlDecimal.Null;
3016
3017             if (n.m_bScale == 0)
3018                 return n;
3019
3020             bool fFraction;    //Fractional flag
3021
3022             n.MakeInteger(out fFraction);
3023
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) {
3027                 n.AddULong(1);
3028             }
3029
3030             if (n.FZero())//if result is zero, sign should be positive
3031                 n.SetPositive();
3032             n.AssertValid();
3033             return n;
3034         }
3035
3036         // Sign -   1 if positive, -1 if negative
3037         /// <devdoc>
3038         ///    <para>[To be supplied.]</para>
3039         /// </devdoc>
3040         public static SqlInt32 Sign(SqlDecimal n) {
3041             n.AssertValid();
3042
3043             if (n.IsNull)
3044                 return SqlInt32.Null;
3045
3046             if (n == new SqlDecimal(0))
3047                 return SqlInt32.Zero;
3048             else
3049                 return n.IsNull ? SqlInt32.Null :
3050                     (n.IsPositive ? new SqlInt32(1) : new SqlInt32(-1));
3051         }
3052
3053         private static SqlDecimal Round(SqlDecimal n, int lPosition, bool fTruncate) {
3054             if (n.IsNull)
3055                 return SqlDecimal.Null;
3056
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
3062             }
3063             else {
3064                 //If round to the left of the decimal point
3065                 lPosition = Math.Max(-NUMERIC_MAX_PRECISION, lPosition);
3066
3067                 //Return +0.00 if truncation of integer part
3068                 if (lPosition < n.m_bScale - n.m_bPrec) {
3069                     n.SetToZero();
3070                     return n;
3071                 }
3072             }
3073
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;                                 //
3077
3078             //Compute the integral part of the numeric
3079             while (lAdjust > 0) {
3080                 if (lAdjust >= 9) {
3081                     ulRem = n.DivByULong (x_rgulShiftBase[8]);
3082                     ulLastDivBase = x_rgulShiftBase[8];
3083                     lAdjust -= 9;
3084                 }
3085                 else {
3086                     ulRem = n.DivByULong (x_rgulShiftBase[lAdjust-1]);
3087                     ulLastDivBase = x_rgulShiftBase[lAdjust-1];
3088                     lAdjust = 0;
3089                 }
3090             }
3091
3092             // The rounding only depends on the first digit after the rounding position
3093             if (ulLastDivBase > 1) {
3094                 ulRem /= (ulLastDivBase / 10);
3095             }
3096
3097             //If result is zero, return
3098             if (n.FZero() && (fTruncate || ulRem < 5))
3099                 {
3100                 n.SetPositive();
3101                 n.AssertValid();
3102                 return n;
3103                 }
3104
3105             // Adjust by adding 1 if remainder is larger than 5
3106             if (ulRem >= 5 && !fTruncate)
3107                 n.AddULong(1);
3108
3109             // Convert back to original scale
3110             lAdjust = Math.Abs(lPosition - n.m_bScale);
3111
3112             while (lAdjust-- > 0) {
3113                 n.MultByULong(x_ulBase10);
3114             }
3115
3116             n.AssertValid();
3117             return n;
3118         }
3119
3120         // Round - Round the numeric to a specific digit
3121         /// <devdoc>
3122         ///    <para>[To be supplied.]</para>
3123         /// </devdoc>
3124         public static SqlDecimal Round(SqlDecimal n, int position) {
3125             n.AssertValid();
3126             return Round(n, position, false);
3127         }
3128
3129         // Truncate - Truncate the numeric to a specific digit
3130         /// <devdoc>
3131         ///    <para>[To be supplied.]</para>
3132         /// </devdoc>
3133         public static SqlDecimal Truncate(SqlDecimal n, int position) {
3134             n.AssertValid();
3135             return Round(n, position, true);
3136         }
3137
3138         // Power - Compute the power of a numeric
3139         /// <devdoc>
3140         ///    <para>[To be supplied.]</para>
3141         /// </devdoc>
3142         public static SqlDecimal Power(SqlDecimal n, double exp) {
3143             n.AssertValid();
3144
3145             if (n.IsNull)
3146                 return SqlDecimal.Null;
3147
3148             byte prec = n.Precision;
3149             int scale = n.Scale;
3150             double dBaseNum = n.ToDouble();
3151
3152             n = new SqlDecimal(Math.Pow(dBaseNum, exp));
3153             n.AdjustScale(scale - (int)n.Scale, true);
3154
3155             n.m_bPrec = MaxPrecision;
3156
3157             return n;
3158         }
3159
3160
3161         // IComparable
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.
3168         /// <devdoc>
3169         ///    <para>[To be supplied.]</para>
3170         /// </devdoc>
3171         public int CompareTo(Object value) {
3172             if (value is SqlDecimal) {
3173                 SqlDecimal i = (SqlDecimal)value;
3174
3175                 return CompareTo(i);
3176             }
3177             throw ADP.WrongType(value.GetType(), typeof(SqlDecimal));
3178         }
3179
3180         public int CompareTo(SqlDecimal value) {
3181             // If both Null, consider them equal.
3182             // Otherwise, Null is less than anything.
3183             if (IsNull)
3184                 return value.IsNull ? 0  : -1;
3185             else if (value.IsNull)
3186                 return 1;
3187
3188             if (this < value) return -1;
3189             if (this > value) return 1;
3190             return 0;
3191         }
3192
3193         // Compares this instance with a specified object
3194         /// <devdoc>
3195         ///    <para>[To be supplied.]</para>
3196         /// </devdoc>
3197         public override bool Equals(Object value) {
3198             if (!(value is SqlDecimal)) {
3199                 return false;
3200             }
3201
3202             SqlDecimal i = (SqlDecimal)value;
3203
3204             if (i.IsNull || IsNull)
3205                 return (i.IsNull && IsNull);
3206             else
3207                 return (this == i).Value;
3208         }
3209
3210         // For hashing purpose
3211         /// <devdoc>
3212         ///    <para>[To be supplied.]</para>
3213         /// </devdoc>
3214         public override int GetHashCode() {
3215             if (IsNull)
3216                 return 0;
3217
3218             SqlDecimal ssnumTemp;
3219             int        lActualPrec;
3220
3221             // First, "normalize" numeric, so that values with different
3222             // scale/precision will have the same representation.
3223             ssnumTemp = this;
3224             lActualPrec = ssnumTemp.CalculatePrecision();
3225             ssnumTemp.AdjustScale(NUMERIC_MAX_PRECISION - lActualPrec, true);
3226
3227             // Now evaluate the hash
3228             int cDwords = ssnumTemp.m_bLen;
3229             int ulValue = 0;
3230             int ulHi;
3231
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;
3236
3237             int[] rgiData = ssnumTemp.Data;
3238
3239             for (int i = 0; i < cDwords; i++)
3240                 {
3241                 ulHi = (ulValue >> iShiftVal) & 0xff;
3242                 ulValue <<= x_cbCrcWindow;
3243                 ulValue = ulValue ^ rgiData[i] ^ ulHi;
3244                 }
3245             return ulValue;
3246         }
3247
3248         /// <devdoc>
3249         ///    <para>[To be supplied.]</para>
3250         /// </devdoc>
3251         XmlSchema IXmlSerializable.GetSchema() { return null; }
3252
3253         /// <devdoc>
3254         ///    <para>[To be supplied.]</para>
3255         /// </devdoc>
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);
3262             }
3263             else {
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;
3273             }
3274         }
3275
3276         /// <devdoc>
3277         ///    <para>[To be supplied.]</para>
3278         /// </devdoc>
3279         void IXmlSerializable.WriteXml(XmlWriter writer) {
3280             if (IsNull) {
3281                 writer.WriteAttributeString("xsi", "nil", XmlSchema.InstanceNamespace, "true");
3282             }
3283             else {
3284                 writer.WriteString(ToString());
3285             }
3286         }
3287
3288         /// <devdoc>
3289         ///    <para>[To be supplied.]</para>
3290         /// </devdoc>
3291         public static XmlQualifiedName GetXsdType(XmlSchemaSet schemaSet) {
3292             return new XmlQualifiedName("decimal", XmlSchema.Namespace);
3293         }
3294
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.
3297
3298         /// <devdoc>
3299         ///    <para>[To be supplied.]</para>
3300         /// </devdoc>
3301         public static readonly SqlDecimal Null = new SqlDecimal(true);
3302
3303         /// <devdoc>
3304         ///    <para>[To be supplied.]</para>
3305         /// </devdoc>
3306         public static readonly SqlDecimal MinValue    = SqlDecimal.Parse("-99999999999999999999999999999999999999");
3307         /// <devdoc>
3308         ///    <para>[To be supplied.]</para>
3309         /// </devdoc>
3310         public static readonly SqlDecimal MaxValue    = SqlDecimal.Parse("99999999999999999999999999999999999999");
3311
3312     } // SqlDecimal
3313
3314 } // namespace System.Data.SqlTypes