merged Sys.Web.Services 2.0 support in my branch:
[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
38 #if NET_2_0
39 using System.Runtime.ConstrainedExecution;
40 #endif
41
42 namespace System {
43         
44         [Serializable]
45         public struct Double : IComparable, IFormattable, IConvertible
46 #if NET_2_0
47                 , IComparable <double>, IEquatable <double>
48 #endif
49         {
50                 public const double Epsilon = 4.9406564584124650e-324;
51                 public const double MaxValue =  1.7976931348623157e308;
52                 public const double MinValue = -1.7976931348623157e308;
53                 public const double NaN = 0.0d / 0.0d;
54                 public const double NegativeInfinity = -1.0d / 0.0d;
55                 public const double PositiveInfinity = 1.0d / 0.0d;
56                 
57                 internal double m_value;
58
59                 public int CompareTo (object v)
60                 {
61                         if (v == null)
62                                 return 1;
63                         
64                         if (!(v is System.Double))
65                                 throw new ArgumentException (Locale.GetText ("Value is not a System.Double"));
66
67                         double dv = (double)v;
68
69                         if (IsPositiveInfinity(m_value) && IsPositiveInfinity(dv))
70                                 return 0;
71
72                         if (IsNegativeInfinity(m_value) && IsNegativeInfinity(dv))
73                                 return 0;
74
75                         if (IsNaN(dv))
76                                 if (IsNaN(m_value))
77                                         return 0;
78                                 else
79                                         return 1;
80
81                         if (IsNaN(m_value))
82                                 if (IsNaN(dv))
83                                         return 0;
84                                 else
85                                         return -1;
86
87                         if (m_value > dv) return 1;
88                         else if (m_value < dv) return -1;
89                         else return 0;
90                 }
91
92                 public override bool Equals (object o)
93                 {
94                         if (!(o is System.Double))
95                                 return false;
96
97                         if (IsNaN ((double)o)) {
98                                 if (IsNaN(m_value))
99                                         return true;
100                                 else
101                                         return false;
102                         }
103
104                         return ((double) o) == m_value;
105                 }
106
107 #if NET_2_0
108                 public int CompareTo (double value)
109                 {
110                         if (IsPositiveInfinity(m_value) && IsPositiveInfinity(value))
111                                 return 0;
112
113                         if (IsNegativeInfinity(m_value) && IsNegativeInfinity(value))
114                                 return 0;
115
116                         if (IsNaN(value))
117                                 if (IsNaN(m_value))
118                                         return 0;
119                                 else
120                                         return 1;
121
122                         if (IsNaN(m_value))
123                                 if (IsNaN(value))
124                                         return 0;
125                                 else
126                                         return -1;
127
128                         if (m_value > value) return 1;
129                         else if (m_value < value) return -1;
130                         else return 0;
131                 }
132
133                 public bool Equals (double value)
134                 {
135                         if (IsNaN (value)) {
136                                 if (IsNaN(m_value))
137                                         return true;
138                                 else
139                                         return false;
140                         }
141
142                         return value == m_value;
143                 }
144 #endif
145
146                 public override unsafe int GetHashCode ()
147                 {
148                         double d = m_value;
149                         return (*((long*)&d)).GetHashCode ();
150                 }
151
152                 public static bool IsInfinity (double d)
153                 {
154                         return (d == PositiveInfinity || d == NegativeInfinity);
155                 }
156
157 #if NET_2_0
158                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
159 #endif
160                 public static bool IsNaN (double d)
161                 {
162 #pragma warning disable 1718
163                         return (d != d);
164 #pragma warning restore
165                 }
166
167                 public static bool IsNegativeInfinity (double d)
168                 {
169                         return (d < 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
170                 }
171
172                 public static bool IsPositiveInfinity (double d)
173                 {
174                         return (d > 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
175                 }
176
177                 public static double Parse (string s)
178                 {
179                         return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), null);
180                 }
181
182                 public static double Parse (string s, IFormatProvider fp)
183                 {
184                         return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), fp);
185                 }
186
187                 public static double Parse (string s, NumberStyles style) 
188                 {
189                         return Parse (s, style, null);
190                 }
191
192                 // We're intentionally using constants here to avoid some bigger headaches in mcs.
193                 // This struct must be compiled before System.Enum so we can't use enums here.
194                 private const int State_AllowSign = 1;
195                 private const int State_Digits = 2;
196                 private const int State_Decimal = 3;
197                 private const int State_ExponentSign = 4;
198                 private const int State_Exponent = 5;
199                 private const int State_ConsumeWhiteSpace = 6;
200                 private const int State_Exit = 7;
201                 
202                 public static double Parse (string s, NumberStyles style, IFormatProvider provider)
203                 {
204                         Exception exc;
205                         double result;
206                         
207                         if (!Parse (s, style, provider, false, out result, out exc))
208                                 throw exc;
209
210                         return result;
211                 }
212                 
213                 // FIXME: check if digits are group in correct numbers between the group separators
214                 internal static bool Parse (string s, NumberStyles style, IFormatProvider provider, bool tryParse, out double result, out Exception exc)
215                 {
216                         result = 0;
217                         exc = null;
218                         
219                         if (s == null) {
220                                 if (!tryParse)
221                                         exc = new ArgumentNullException ("s");
222                                 return false;
223                         }
224                         if (s.Length == 0) {
225                                 if (!tryParse)
226                                         exc = new FormatException ();
227                                 return false;
228                         }
229 #if NET_2_0
230                         // yes it's counter intuitive (buggy?) but even TryParse actually throws in this case
231                         if ((style & NumberStyles.AllowHexSpecifier) != 0) {
232                                 string msg = Locale.GetText ("Double doesn't support parsing with '{0}'.", "AllowHexSpecifier");
233                                 throw new ArgumentException (msg);
234                         }
235 #endif
236                         if (style > NumberStyles.Any) {
237                                 if (!tryParse)
238                                         exc = new ArgumentException();
239                                 return false;
240                         }
241
242                         NumberFormatInfo format = NumberFormatInfo.GetInstance(provider);
243                         if (format == null) throw new Exception("How did this happen?");
244                         
245                         if (s == format.NaNSymbol) {
246                                 result = Double.NaN;
247                                 return true;
248                         }
249                         if (s == format.PositiveInfinitySymbol) {
250                                 result = Double.PositiveInfinity;
251                                 return true;
252                         }
253                         if (s == format.NegativeInfinitySymbol) {
254                                 result = Double.NegativeInfinity;
255                                 return true;
256                         }
257
258                         //
259                         // validate and prepare string for C
260                         //
261                         int len = s.Length;
262                         byte [] b = new byte [len + 1];
263                         int didx = 0;
264                         int sidx = 0;
265                         char c;
266                         
267                         if ((style & NumberStyles.AllowLeadingWhite) != 0){
268                                 while (sidx < len && Char.IsWhiteSpace (c = s [sidx]))
269                                        sidx++;
270
271                                 if (sidx == len) {
272                                         if (!tryParse)
273                                                 exc = Int32.GetFormatException ();
274                                         return true;
275                                 }
276                         }
277
278                         bool allow_trailing_white = ((style & NumberStyles.AllowTrailingWhite) != 0);
279
280                         //
281                         // Machine state
282                         //
283                         int state = State_AllowSign;
284
285                         //
286                         // Setup
287                         //
288                         string decimal_separator = null;
289                         string group_separator = null;
290                         string currency_symbol = null;
291                         int decimal_separator_len = 0;
292                         int group_separator_len = 0;
293                         int currency_symbol_len = 0;
294                         if ((style & NumberStyles.AllowDecimalPoint) != 0){
295                                 decimal_separator = format.NumberDecimalSeparator;
296                                 decimal_separator_len = decimal_separator.Length;
297                         }
298                         if ((style & NumberStyles.AllowThousands) != 0){
299                                 group_separator = format.NumberGroupSeparator;
300                                 group_separator_len = group_separator.Length;
301                         }
302                         if ((style & NumberStyles.AllowCurrencySymbol) != 0){
303                                 currency_symbol = format.CurrencySymbol;
304                                 currency_symbol_len = currency_symbol.Length;
305                         }
306                         string positive = format.PositiveSign;
307                         string negative = format.NegativeSign;
308                         
309                         for (; sidx < len; sidx++){
310                                 c = s [sidx];
311
312                                 if (c == '\0') {
313                                         sidx = len;
314                                         continue;
315                                 }
316
317                                 switch (state){
318                                 case State_AllowSign:
319                                         if ((style & NumberStyles.AllowLeadingSign) != 0){
320                                                 if (c == positive [0] &&
321                                                     s.Substring (sidx, positive.Length) == positive){
322                                                         state = State_Digits;
323                                                         sidx += positive.Length-1;
324                                                         continue;
325                                                 }
326
327                                                 if (c == negative [0] &&
328                                                     s.Substring (sidx, negative.Length) == negative){
329                                                         state = State_Digits;
330                                                         b [didx++] = (byte) '-';
331                                                         sidx += negative.Length-1;
332                                                         continue;
333                                                 }
334                                         }
335                                         state = State_Digits;
336                                         goto case State_Digits;
337                                         
338                                 case State_Digits:
339                                         if (Char.IsDigit (c)){
340                                                 b [didx++] = (byte) c;
341                                                 break;
342                                         }
343                                         if (c == 'e' || c == 'E')
344                                                 goto case State_Decimal;
345                                         
346                                         if (decimal_separator != null &&
347                                             decimal_separator [0] == c) {
348                                                 if (String.CompareOrdinal (s, sidx, decimal_separator, 0, decimal_separator_len) == 0) {
349                                                         b [didx++] = (byte) '.';
350                                                         sidx += decimal_separator_len-1;
351                                                         state = State_Decimal; 
352                                                         break;
353                                                 }
354                                         }
355                                         if (group_separator != null &&
356                                             group_separator [0] == c){
357                                                 if (s.Substring (sidx, group_separator_len) ==
358                                                     group_separator){
359                                                         sidx += group_separator_len-1;
360                                                         state = State_Digits; 
361                                                         break;
362                                                 }
363                                         }
364                                         if (currency_symbol != null &&
365                                             currency_symbol [0] == c){
366                                                 if (s.Substring (sidx, currency_symbol_len) ==
367                                                     currency_symbol){
368                                                         sidx += currency_symbol_len-1;
369                                                         state = State_Digits; 
370                                                         break;
371                                                 }
372                                         }
373                                         
374                                         if (Char.IsWhiteSpace (c))
375                                                 goto case State_ConsumeWhiteSpace;
376
377                                         if (!tryParse)
378                                                 exc = new FormatException ("Unknown char: " + c);
379                                         return false;
380
381                                 case State_Decimal:
382                                         if (Char.IsDigit (c)){
383                                                 b [didx++] = (byte) c;
384                                                 break;
385                                         }
386
387                                         if (c == 'e' || c == 'E'){
388                                                 if ((style & NumberStyles.AllowExponent) == 0) {
389                                                         if (!tryParse)
390                                                                 exc = new FormatException ("Unknown char: " + c);
391                                                         return false;
392                                                 }
393                                                 b [didx++] = (byte) c;
394                                                 state = State_ExponentSign;
395                                                 break;
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_ExponentSign:
406                                         if (Char.IsDigit (c)){
407                                                 state = State_Exponent;
408                                                 goto case State_Exponent;
409                                         }
410
411                                         if (c == positive [0] &&
412                                             s.Substring (sidx, positive.Length) == positive){
413                                                 state = State_Digits;
414                                                 sidx += positive.Length-1;
415                                                 continue;
416                                         }
417
418                                         if (c == negative [0] &&
419                                             s.Substring (sidx, negative.Length) == negative){
420                                                 state = State_Digits;
421                                                 b [didx++] = (byte) '-';
422                                                 sidx += negative.Length-1;
423                                                 continue;
424                                         }
425
426                                         if (Char.IsWhiteSpace (c))
427                                                 goto case State_ConsumeWhiteSpace;
428                                         
429                                         if (!tryParse)
430                                                 exc = new FormatException ("Unknown char: " + c);
431                                         return false;
432                                         
433                                 case State_Exponent:
434                                         if (Char.IsDigit (c)){
435                                                 b [didx++] = (byte) c;
436                                                 break;
437                                         }
438                                         
439                                         if (Char.IsWhiteSpace (c))
440                                                 goto case State_ConsumeWhiteSpace;
441                                         
442                                         if (!tryParse)
443                                                 exc = new FormatException ("Unknown char: " + c);
444                                         return false;
445
446                                 case State_ConsumeWhiteSpace:
447                                         if (allow_trailing_white && Char.IsWhiteSpace (c)) {
448                                                 state = State_Exit;
449                                                 break;
450                                         }
451                                         
452                                         if (!tryParse)
453                                                 exc = new FormatException ("Unknown char");
454                                         return false;
455                                 }
456
457                                 if (state == State_Exit)
458                                         break;
459                         }
460
461                         b [didx] = 0;
462                         unsafe {
463                                 fixed (byte *p = &b [0]){
464                                         double retVal;
465                                         if (!ParseImpl (p, out retVal)) {
466                                                 if (!tryParse)
467                                                         exc = Int32.GetFormatException ();
468                                                 return false;
469                                         }
470                                         if (IsPositiveInfinity(retVal) || IsNegativeInfinity(retVal)) {
471                                                 if (!tryParse)
472                                                         exc = new OverflowException ();
473                                                 return false;
474                                         }
475
476                                         result = retVal;
477                                         return true;
478                                 }
479                         }
480                 }
481
482                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
483                 unsafe private static extern bool ParseImpl (byte *byte_ptr, out double value);
484                 
485                 public static bool TryParse (string s,
486                                              NumberStyles style,
487                                              IFormatProvider provider,
488                                              out double result)
489                 {
490                         Exception exc;
491                         if (!Parse (s, style, provider, true, out result, out exc)) {
492                                 result = 0;
493                                 return false;
494                         }
495
496                         return true;
497                 }
498 #if NET_2_0
499                 public static bool TryParse (string s, out double result)
500                 {
501                         return TryParse (s, NumberStyles.Any, null, out result);
502                 }
503 #endif
504                 public override string ToString ()
505                 {
506                         return ToString (null, null);
507                 }
508
509                 public string ToString (IFormatProvider fp)
510                 {
511                         return ToString (null, fp);
512                 }
513
514                 public string ToString (string format)
515                 {
516                         return ToString (format, null);
517                 }
518
519                 public string ToString (string format, IFormatProvider fp)
520                 {
521                         NumberFormatInfo nfi = NumberFormatInfo.GetInstance (fp);
522                         return NumberFormatter.NumberToString (format, m_value, nfi);
523                 }
524
525                 // =========== IConvertible Methods =========== //
526
527                 public TypeCode GetTypeCode ()
528                 {
529                         return TypeCode.Double;
530                 }
531
532                 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
533                 {
534                         return System.Convert.ToType(m_value, conversionType, provider);
535                 }
536                 
537                 bool IConvertible.ToBoolean (IFormatProvider provider)
538                 {
539                         return System.Convert.ToBoolean(m_value);
540                 }
541                 
542                 byte IConvertible.ToByte (IFormatProvider provider)
543                 {
544                         return System.Convert.ToByte(m_value);
545                 }
546                 
547                 char IConvertible.ToChar (IFormatProvider provider)
548                 {
549                         throw new InvalidCastException();
550                 }
551                 
552                 DateTime IConvertible.ToDateTime (IFormatProvider provider)
553                 {
554                         throw new InvalidCastException();
555                 }
556                 
557                 decimal IConvertible.ToDecimal (IFormatProvider provider)
558                 {
559                         return System.Convert.ToDecimal(m_value);
560                 }
561                 
562                 double IConvertible.ToDouble (IFormatProvider provider)
563                 {
564                         return System.Convert.ToDouble(m_value);
565                 }
566                 
567                 short IConvertible.ToInt16 (IFormatProvider provider)
568                 {
569                         return System.Convert.ToInt16(m_value);
570                 }
571                 
572                 int IConvertible.ToInt32 (IFormatProvider provider)
573                 {
574                         return System.Convert.ToInt32(m_value);
575                 }
576                 
577                 long IConvertible.ToInt64 (IFormatProvider provider)
578                 {
579                         return System.Convert.ToInt64(m_value);
580                 }
581                 
582                 sbyte IConvertible.ToSByte (IFormatProvider provider)
583                 {
584                         return System.Convert.ToSByte(m_value);
585                 }
586                 
587                 float IConvertible.ToSingle (IFormatProvider provider)
588                 {
589                         return System.Convert.ToSingle(m_value);
590                 }
591                 
592 /*
593                 string IConvertible.ToString (IFormatProvider provider)
594                 {
595                         return ToString(provider);
596                 }
597 */
598
599                 ushort IConvertible.ToUInt16 (IFormatProvider provider)
600                 {
601                         return System.Convert.ToUInt16(m_value);
602                 }
603                 
604                 uint IConvertible.ToUInt32 (IFormatProvider provider)
605                 {
606                         return System.Convert.ToUInt32(m_value);
607                 }
608                 
609                 ulong IConvertible.ToUInt64 (IFormatProvider provider)
610                 {
611                         return System.Convert.ToUInt64(m_value);
612                 }
613         }
614 }