SqlBulkCopy Implementation
[mono.git] / mcs / class / corlib / System / Double.cs
1 //
2 // System.Double.cs
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Bob Smith       (bob@thestuff.net)
7 //
8 // (C) Ximian, Inc.  http://www.ximian.com
9 // (C) Bob Smith.    http://www.thestuff.net
10 //
11
12 //
13 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 //
34
35 using System.Globalization;
36 using System.Runtime.CompilerServices;
37 using System.Runtime.ConstrainedExecution;
38
39 namespace System {
40         
41         [Serializable]
42         [System.Runtime.InteropServices.ComVisible (true)]
43         public struct Double : IComparable, IFormattable, IConvertible, IComparable <double>, IEquatable <double>
44         {
45                 public const double Epsilon = 4.9406564584124650e-324;
46                 public const double MaxValue =  1.7976931348623157e308;
47                 public const double MinValue = -1.7976931348623157e308;
48                 public const double NaN = 0.0d / 0.0d;
49                 public const double NegativeInfinity = -1.0d / 0.0d;
50                 public const double PositiveInfinity = 1.0d / 0.0d;
51                 
52                 internal double m_value;
53
54                 public int CompareTo (object value)
55                 {
56                         if (value == null)
57                                 return 1;
58                         
59                         if (!(value is System.Double))
60                                 throw new ArgumentException (Locale.GetText ("Value is not a System.Double"));
61
62                         double dv = (double)value;
63
64                         if (IsPositiveInfinity(m_value) && IsPositiveInfinity(dv))
65                                 return 0;
66
67                         if (IsNegativeInfinity(m_value) && IsNegativeInfinity(dv))
68                                 return 0;
69
70                         if (IsNaN(dv))
71                                 if (IsNaN(m_value))
72                                         return 0;
73                                 else
74                                         return 1;
75
76                         if (IsNaN(m_value))
77                                 if (IsNaN(dv))
78                                         return 0;
79                                 else
80                                         return -1;
81
82                         if (m_value > dv) return 1;
83                         else if (m_value < dv) return -1;
84                         else return 0;
85                 }
86
87                 public override bool Equals (object obj)
88                 {
89                         if (!(obj is System.Double))
90                                 return false;
91
92                         double value = (double) obj;
93
94                         if (IsNaN (value))
95                                 return IsNaN (m_value);
96
97                         return (value == m_value);
98                 }
99
100                 public int CompareTo (double value)
101                 {
102                         if (IsPositiveInfinity(m_value) && IsPositiveInfinity(value))
103                                 return 0;
104
105                         if (IsNegativeInfinity(m_value) && IsNegativeInfinity(value))
106                                 return 0;
107
108                         if (IsNaN(value))
109                                 if (IsNaN(m_value))
110                                         return 0;
111                                 else
112                                         return 1;
113
114                         if (IsNaN(m_value))
115                                 if (IsNaN(value))
116                                         return 0;
117                                 else
118                                         return -1;
119
120                         if (m_value > value) return 1;
121                         else if (m_value < value) return -1;
122                         else return 0;
123                 }
124
125                 public bool Equals (double obj)
126                 {
127                         if (IsNaN (obj)) {
128                                 if (IsNaN(m_value))
129                                         return true;
130                                 else
131                                         return false;
132                         }
133
134                         return obj == m_value;
135                 }
136
137                 public override unsafe int GetHashCode ()
138                 {
139                         double d = m_value;
140                         return (*((long*)&d)).GetHashCode ();
141                 }
142
143 #if     NET_4_0
144                 public static bool operator==(double left, double right)
145                 {
146                         return left == right;
147                 }
148
149                 public static bool operator!=(double left, double right)
150                 {
151                         return left != right;
152                 }
153
154                 public static bool operator>(double left, double right)
155                 {
156                         return left > right;
157                 }
158
159                 public static bool operator>=(double left, double right)
160                 {
161                         return left >= right;
162                 }
163
164                 public static bool operator<(double left, double right)
165                 {
166                         return left < right;
167                 }
168
169                 public static bool operator<=(double left, double right)
170                 {
171                         return left <= right;
172                 }
173 #endif
174
175                 public static bool IsInfinity (double d)
176                 {
177                         return (d == PositiveInfinity || d == NegativeInfinity);
178                 }
179
180                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
181                 public static bool IsNaN (double d)
182                 {
183 #pragma warning disable 1718
184                         return (d != d);
185 #pragma warning restore
186                 }
187
188                 public static bool IsNegativeInfinity (double d)
189                 {
190                         return (d < 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
191                 }
192
193                 public static bool IsPositiveInfinity (double d)
194                 {
195                         return (d > 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
196                 }
197
198                 public static double Parse (string s)
199                 {
200                         return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), null);
201                 }
202
203                 public static double Parse (string s, IFormatProvider provider)
204                 {
205                         return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), provider);
206                 }
207
208                 public static double Parse (string s, NumberStyles style) 
209                 {
210                         return Parse (s, style, null);
211                 }
212
213                 // We're intentionally using constants here to avoid some bigger headaches in mcs.
214                 // This struct must be compiled before System.Enum so we can't use enums here.
215                 private const int State_AllowSign = 1;
216                 private const int State_Digits = 2;
217                 private const int State_Decimal = 3;
218                 private const int State_ExponentSign = 4;
219                 private const int State_Exponent = 5;
220                 private const int State_ConsumeWhiteSpace = 6;
221                 private const int State_Exit = 7;
222                 
223                 public static double Parse (string s, NumberStyles style, IFormatProvider provider)
224                 {
225                         Exception exc;
226                         double result;
227                         
228                         if (!Parse (s, style, provider, false, out result, out exc))
229                                 throw exc;
230
231                         return result;
232                 }
233                 
234                 // FIXME: check if digits are group in correct numbers between the group separators
235                 internal static bool Parse (string s, NumberStyles style, IFormatProvider provider, bool tryParse, out double result, out Exception exc)
236                 {
237                         result = 0;
238                         exc = null;
239                         
240                         if (s == null) {
241                                 if (!tryParse)
242                                         exc = new ArgumentNullException ("s");
243                                 return false;
244                         }
245                         if (s.Length == 0) {
246                                 if (!tryParse)
247                                         exc = new FormatException ();
248                                 return false;
249                         }
250                         // yes it's counter intuitive (buggy?) but even TryParse actually throws in this case
251                         if ((style & NumberStyles.AllowHexSpecifier) != 0) {
252                                 string msg = Locale.GetText ("Double doesn't support parsing with '{0}'.", "AllowHexSpecifier");
253                                 throw new ArgumentException (msg);
254                         }
255                         if (style > NumberStyles.Any) {
256                                 if (!tryParse)
257                                         exc = new ArgumentException();
258                                 return false;
259                         }
260
261                         NumberFormatInfo format = NumberFormatInfo.GetInstance(provider);
262                         if (format == null) throw new Exception("How did this happen?");
263                         
264                         //
265                         // validate and prepare string for C
266                         //
267                         int len = s.Length;
268                         int didx = 0;
269                         int sidx = 0;
270                         char c;
271                         bool allow_leading_white = (style & NumberStyles.AllowLeadingWhite) != 0;
272                         bool allow_trailing_white = ((style & NumberStyles.AllowTrailingWhite) != 0);
273                         
274                         if (allow_leading_white) {
275                                 while (sidx < len && Char.IsWhiteSpace (s [sidx]))
276                                        sidx++;
277
278                                 if (sidx == len) {
279                                         if (!tryParse)
280                                                 exc = Int32.GetFormatException ();
281                                         return false;
282                                 }
283                         }
284                         int sEndPos = s.Length - 1;
285                         if (allow_trailing_white)
286                                 while (Char.IsWhiteSpace (s [sEndPos]))
287                                         sEndPos--;
288
289                         if (TryParseStringConstant (format.NaNSymbol, s, sidx, sEndPos)) {
290                                 result = double.NaN;
291                                 return true;
292                         }
293                         if (TryParseStringConstant (format.PositiveInfinitySymbol, s, sidx, sEndPos)) {
294                                 result = double.PositiveInfinity;
295                                 return true;
296                         }
297                         if (TryParseStringConstant (format.NegativeInfinitySymbol, s, sidx, sEndPos)) {
298                                 result = double.NegativeInfinity;
299                                 return true;
300                         }
301
302                         byte [] b = new byte [len + 1];
303
304                         //
305                         // Machine state
306                         //
307                         int state = State_AllowSign;
308
309                         //
310                         // Setup
311                         //
312                         string decimal_separator = null;
313                         string group_separator = null;
314                         string currency_symbol = null;
315                         int decimal_separator_len = 0;
316                         int group_separator_len = 0;
317                         int currency_symbol_len = 0;
318                         if ((style & NumberStyles.AllowDecimalPoint) != 0){
319                                 decimal_separator = format.NumberDecimalSeparator;
320                                 decimal_separator_len = decimal_separator.Length;
321                         }
322                         if ((style & NumberStyles.AllowThousands) != 0){
323                                 group_separator = format.NumberGroupSeparator;
324                                 group_separator_len = group_separator.Length;
325                         }
326                         if ((style & NumberStyles.AllowCurrencySymbol) != 0){
327                                 currency_symbol = format.CurrencySymbol;
328                                 currency_symbol_len = currency_symbol.Length;
329                         }
330                         string positive = format.PositiveSign;
331                         string negative = format.NegativeSign;
332                         
333                         for (; sidx < len; sidx++){
334                                 c = s [sidx];
335
336                                 if (c == '\0') {
337                                         sidx = len;
338                                         continue;
339                                 }
340
341                                 switch (state){
342                                 case State_AllowSign:
343                                         if ((style & NumberStyles.AllowLeadingSign) != 0){
344                                                 if (c == positive [0] &&
345                                                     s.Substring (sidx, positive.Length) == positive){
346                                                         state = State_Digits;
347                                                         sidx += positive.Length-1;
348                                                         continue;
349                                                 }
350
351                                                 if (c == negative [0] &&
352                                                     s.Substring (sidx, negative.Length) == negative){
353                                                         state = State_Digits;
354                                                         b [didx++] = (byte) '-';
355                                                         sidx += negative.Length-1;
356                                                         continue;
357                                                 }
358                                         }
359                                         state = State_Digits;
360                                         goto case State_Digits;
361                                         
362                                 case State_Digits:
363                                         if (Char.IsDigit (c)){
364                                                 b [didx++] = (byte) c;
365                                                 break;
366                                         }
367                                         if (c == 'e' || c == 'E')
368                                                 goto case State_Decimal;
369                                         
370                                         if (decimal_separator_len > 0 &&
371                                             decimal_separator [0] == c) {
372                                                 if (String.CompareOrdinal (s, sidx, decimal_separator, 0, decimal_separator_len) == 0) {
373                                                         b [didx++] = (byte) '.';
374                                                         sidx += decimal_separator_len-1;
375                                                         state = State_Decimal; 
376                                                         break;
377                                                 }
378                                         }
379                                         if (group_separator_len > 0 &&
380                                             group_separator [0] == c){
381                                                 if (s.Substring (sidx, group_separator_len) ==
382                                                     group_separator){
383                                                         sidx += group_separator_len-1;
384                                                         state = State_Digits; 
385                                                         break;
386                                                 }
387                                         }
388                                         if (currency_symbol_len > 0 &&
389                                             currency_symbol [0] == c){
390                                                 if (s.Substring (sidx, currency_symbol_len) ==
391                                                     currency_symbol){
392                                                         sidx += currency_symbol_len-1;
393                                                         state = State_Digits; 
394                                                         break;
395                                                 }
396                                         }
397                                         
398                                         if (Char.IsWhiteSpace (c))
399                                                 goto case State_ConsumeWhiteSpace;
400
401                                         if (!tryParse)
402                                                 exc = new FormatException ("Unknown char: " + c);
403                                         return false;
404
405                                 case State_Decimal:
406                                         if (Char.IsDigit (c)){
407                                                 b [didx++] = (byte) c;
408                                                 break;
409                                         }
410
411                                         if (c == 'e' || c == 'E'){
412                                                 if ((style & NumberStyles.AllowExponent) == 0) {
413                                                         if (!tryParse)
414                                                                 exc = new FormatException ("Unknown char: " + c);
415                                                         return false;
416                                                 }
417                                                 b [didx++] = (byte) c;
418                                                 state = State_ExponentSign;
419                                                 break;
420                                         }
421                                         
422                                         if (Char.IsWhiteSpace (c))
423                                                 goto case State_ConsumeWhiteSpace;
424                                         
425                                         if (!tryParse)
426                                                 exc = new FormatException ("Unknown char: " + c);
427                                         return false;
428
429                                 case State_ExponentSign:
430                                         if (Char.IsDigit (c)){
431                                                 state = State_Exponent;
432                                                 goto case State_Exponent;
433                                         }
434
435                                         if (c == positive [0] &&
436                                             s.Substring (sidx, positive.Length) == positive){
437                                                 state = State_Digits;
438                                                 sidx += positive.Length-1;
439                                                 continue;
440                                         }
441
442                                         if (c == negative [0] &&
443                                             s.Substring (sidx, negative.Length) == negative){
444                                                 state = State_Digits;
445                                                 b [didx++] = (byte) '-';
446                                                 sidx += negative.Length-1;
447                                                 continue;
448                                         }
449
450                                         if (Char.IsWhiteSpace (c))
451                                                 goto case State_ConsumeWhiteSpace;
452                                         
453                                         if (!tryParse)
454                                                 exc = new FormatException ("Unknown char: " + c);
455                                         return false;
456                                         
457                                 case State_Exponent:
458                                         if (Char.IsDigit (c)){
459                                                 b [didx++] = (byte) c;
460                                                 break;
461                                         }
462                                         
463                                         if (Char.IsWhiteSpace (c))
464                                                 goto case State_ConsumeWhiteSpace;
465                                         
466                                         if (!tryParse)
467                                                 exc = new FormatException ("Unknown char: " + c);
468                                         return false;
469
470                                 case State_ConsumeWhiteSpace:
471                                         if (allow_trailing_white && Char.IsWhiteSpace (c)) {
472                                                 state = State_ConsumeWhiteSpace;
473                                                 break;
474                                         }
475                                         
476                                         if (!tryParse)
477                                                 exc = new FormatException ("Unknown char");
478                                         return false;
479                                 }
480
481                                 if (state == State_Exit)
482                                         break;
483                         }
484
485                         b [didx] = 0;
486                         unsafe {
487                                 fixed (byte *p = &b [0]){
488                                         double retVal;
489                                         if (!ParseImpl (p, out retVal)) {
490                                                 if (!tryParse)
491                                                         exc = Int32.GetFormatException ();
492                                                 return false;
493                                         }
494                                         if (IsPositiveInfinity(retVal) || IsNegativeInfinity(retVal)) {
495                                                 if (!tryParse)
496                                                         exc = new OverflowException ();
497                                                 return false;
498                                         }
499
500                                         result = retVal;
501                                         return true;
502                                 }
503                         }
504                 }
505
506                 static bool TryParseStringConstant (string format, string s, int start, int end)
507                 {
508                         return end - start + 1 == format.Length && String.CompareOrdinal (format, 0, s, start, format.Length) == 0;
509                 }
510
511                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
512                 unsafe private static extern bool ParseImpl (byte *byte_ptr, out double value);
513                 
514                 public static bool TryParse (string s,
515                                              NumberStyles style,
516                                              IFormatProvider provider,
517                                              out double result)
518                 {
519                         Exception exc;
520                         if (!Parse (s, style, provider, true, out result, out exc)) {
521                                 result = 0;
522                                 return false;
523                         }
524
525                         return true;
526                 }
527
528                 public static bool TryParse (string s, out double result)
529                 {
530                         return TryParse (s, NumberStyles.Any, null, out result);
531                 }
532
533                 public override string ToString ()
534                 {
535                         return NumberFormatter.NumberToString (m_value, null);
536                 }
537
538                 public string ToString (IFormatProvider provider)
539                 {
540                         return NumberFormatter.NumberToString (m_value, provider);
541                 }
542
543                 public string ToString (string format)
544                 {
545                         return ToString (format, null);
546                 }
547
548                 public string ToString (string format, IFormatProvider provider)
549                 {
550                         return NumberFormatter.NumberToString (format, m_value, provider);
551                 }
552
553                 // =========== IConvertible Methods =========== //
554
555                 public TypeCode GetTypeCode ()
556                 {
557                         return TypeCode.Double;
558                 }
559
560                 object IConvertible.ToType (Type targetType, IFormatProvider provider)
561                 {
562                         if (targetType == null)
563                                 throw new ArgumentNullException ("targetType");
564                         return System.Convert.ToType (m_value, targetType, provider, false);
565                 }
566
567                 bool IConvertible.ToBoolean (IFormatProvider provider)
568                 {
569                         return System.Convert.ToBoolean (m_value);
570                 }
571
572                 byte IConvertible.ToByte (IFormatProvider provider)
573                 {
574                         return System.Convert.ToByte (m_value);
575                 }
576
577                 char IConvertible.ToChar (IFormatProvider provider)
578                 {
579                         throw new InvalidCastException ();
580                 }
581
582                 DateTime IConvertible.ToDateTime (IFormatProvider provider)
583                 {
584                         throw new InvalidCastException ();
585                 }
586
587                 decimal IConvertible.ToDecimal (IFormatProvider provider)
588                 {
589                         return System.Convert.ToDecimal (m_value);
590                 }
591
592                 double IConvertible.ToDouble (IFormatProvider provider)
593                 {
594                         return System.Convert.ToDouble (m_value);
595                 }
596
597                 short IConvertible.ToInt16 (IFormatProvider provider)
598                 {
599                         return System.Convert.ToInt16 (m_value);
600                 }
601
602                 int IConvertible.ToInt32 (IFormatProvider provider)
603                 {
604                         return System.Convert.ToInt32 (m_value);
605                 }
606
607                 long IConvertible.ToInt64 (IFormatProvider provider)
608                 {
609                         return System.Convert.ToInt64 (m_value);
610                 }
611
612                 sbyte IConvertible.ToSByte (IFormatProvider provider)
613                 {
614                         return System.Convert.ToSByte (m_value);
615                 }
616
617                 float IConvertible.ToSingle (IFormatProvider provider)
618                 {
619                         return System.Convert.ToSingle (m_value);
620                 }
621
622                 ushort IConvertible.ToUInt16 (IFormatProvider provider)
623                 {
624                         return System.Convert.ToUInt16 (m_value);
625                 }
626                 uint IConvertible.ToUInt32 (IFormatProvider provider)
627                 {
628                         return System.Convert.ToUInt32 (m_value);
629                 }
630                 ulong IConvertible.ToUInt64 (IFormatProvider provider)
631                 {
632                         return System.Convert.ToUInt64 (m_value);
633                 }
634         }
635 }