Removed useless [CLSCompliant(false)]
[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 using System.Globalization;
13 using System.Runtime.CompilerServices;
14
15 namespace System {
16         
17         [Serializable]
18         public struct Double : IComparable, IFormattable, IConvertible {
19                 public const double Epsilon = 4.9406564584124650e-324;
20                 public const double MaxValue =  1.7976931348623157e308;
21                 public const double MinValue = -1.7976931348623157e308;
22                 public const double NaN = 0.0d / 0.0d;
23                 public const double NegativeInfinity = -1.0d / 0.0d;
24                 public const double PositiveInfinity = 1.0d / 0.0d;
25                 
26                 internal double m_value;
27
28                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
29                 extern internal static void AssertEndianity (out double value);
30
31                 public int CompareTo (object v)
32                 {
33                         if (v == null)
34                                 return 1;
35                         
36                         if (!(v is System.Double))
37                                 throw new ArgumentException (Locale.GetText ("Value is not a System.Double"));
38
39                         double dv = (double)v;
40
41                         if (IsPositiveInfinity(m_value) && IsPositiveInfinity(dv))
42                                 return 0;
43
44                         if (IsNegativeInfinity(m_value) && IsNegativeInfinity(dv))
45                                 return 0;
46
47                         if (IsNaN(dv))
48                                 if (IsNaN(m_value))
49                                         return 0;
50                                 else
51                                         return 1;
52
53                         if (IsNaN(m_value))
54                                 if (IsNaN(dv))
55                                         return 0;
56                                 else
57                                         return -1;
58
59                         if (m_value > dv) return 1;
60                         else if (m_value < dv) return -1;
61                         else return 0;
62                 }
63
64                 public override bool Equals (object o)
65                 {
66                         if (!(o is System.Double))
67                                 return false;
68
69                         if (IsNaN ((double)o)) {
70                                 if (IsNaN(m_value))
71                                         return true;
72                                 else
73                                         return false;
74                         }
75
76                         return ((double) o) == m_value;
77                 }
78
79                 public override int GetHashCode ()
80                 {
81                         return (int) m_value;
82                 }
83
84                 public static bool IsInfinity (double d)
85                 {
86                         return (d == PositiveInfinity || d == NegativeInfinity);
87                 }
88
89                 public static bool IsNaN (double d)
90                 {
91                         return (d != d);
92                 }
93
94                 public static bool IsNegativeInfinity (double d)
95                 {
96                         return (d < 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
97                 }
98
99                 public static bool IsPositiveInfinity (double d)
100                 {
101                         return (d > 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
102                 }
103
104                 public static double Parse (string s)
105                 {
106                         return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), null);
107                 }
108
109                 public static double Parse (string s, IFormatProvider fp)
110                 {
111                         return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), fp);
112                 }
113
114                 public static double Parse (string s, NumberStyles style) 
115                 {
116                         return Parse (s, style, null);
117                 }
118
119                 // We're intentionally using constants here to avoid some bigger headaches in mcs.
120                 // This struct must be compiled before System.Enum so we can't use enums here.
121                 private const int State_AllowSign = 1;
122                 private const int State_Digits = 2;
123                 private const int State_Decimal = 3;
124                 private const int State_ExponentSign = 4;
125                 private const int State_Exponent = 5;
126                 private const int State_ConsumeWhiteSpace = 6;
127                 
128                 [MonoTODO("check if digits are group in correct numbers between the group separators")]
129                 public static double Parse (string s, NumberStyles style, IFormatProvider provider)
130                 {
131                         if (s == null) throw new ArgumentNullException();
132                         if (style > NumberStyles.Any)
133                         {
134                                 throw new ArgumentException();
135                         }
136                         NumberFormatInfo format = NumberFormatInfo.GetInstance(provider);
137                         if (format == null) throw new Exception("How did this happen?");
138                         if (s == format.NaNSymbol) return Double.NaN;
139                         if (s == format.PositiveInfinitySymbol) return Double.PositiveInfinity;
140                         if (s == format.NegativeInfinitySymbol) return Double.NegativeInfinity;
141
142                         //
143                         // validate and prepare string for C
144                         //
145                         int len = s.Length;
146                         byte [] b = new byte [len + 1];
147                         int didx = 0;
148                         int sidx = 0;
149                         char c;
150                         
151                         if ((style & NumberStyles.AllowLeadingWhite) != 0){
152                                 while (sidx < len && Char.IsWhiteSpace (c = s [sidx]))
153                                        sidx++;
154
155                                 if (sidx == len)
156                                         throw new FormatException();
157                         }
158
159                         bool allow_trailing_white = ((style & NumberStyles.AllowTrailingWhite) != 0);
160
161                         //
162                         // Machine state
163                         //
164                         int state = State_AllowSign;
165
166                         //
167                         // Setup
168                         //
169                         string decimal_separator = null;
170                         string group_separator = null;
171                         int decimal_separator_len = 0;
172                         int group_separator_len = 0;
173                         if ((style & NumberStyles.AllowDecimalPoint) != 0){
174                                 decimal_separator = format.NumberDecimalSeparator;
175                                 decimal_separator_len = decimal_separator.Length;
176                         }
177                         if ((style & NumberStyles.AllowThousands) != 0){
178                                 group_separator = format.NumberGroupSeparator;
179                                 group_separator_len = group_separator.Length;
180                         }
181                         string positive = format.PositiveSign;
182                         string negative = format.NegativeSign;
183                         
184                         for (; sidx < len; sidx++){
185                                 c = s [sidx];
186
187                                 switch (state){
188                                 case State_AllowSign:
189                                         if ((style & NumberStyles.AllowLeadingSign) != 0){
190                                                 if (c == positive [0] &&
191                                                     s.Substring (sidx, positive.Length) == positive){
192                                                         state = State_Digits;
193                                                         sidx += positive.Length-1;
194                                                         continue;
195                                                 }
196
197                                                 if (c == negative [0] &&
198                                                     s.Substring (sidx, negative.Length) == negative){
199                                                         state = State_Digits;
200                                                         b [didx++] = (byte) '-';
201                                                         sidx += negative.Length-1;
202                                                         continue;
203                                                 }
204                                         }
205                                         state = State_Digits;
206                                         goto case State_Digits;
207                                         
208                                 case State_Digits:
209                                         if (Char.IsDigit (c)){
210                                                 b [didx++] = (byte) c;
211                                                 break;
212                                         }
213                                         if (c == 'e' || c == 'E')
214                                                 goto case State_Decimal;
215                                         
216                                         if (decimal_separator != null &&
217                                             decimal_separator [0] == c){
218                                                 if (s.Substring (sidx, decimal_separator_len) ==
219                                                     decimal_separator){
220                                                         b [didx++] = (byte) '.';
221                                                         sidx += decimal_separator_len-1;
222                                                         state = State_Decimal; 
223                                                         break;
224                                                 }
225                                         }
226                                         if (group_separator != null &&
227                                             group_separator [0] == c){
228                                                 if (s.Substring (sidx, group_separator_len) ==
229                                                     group_separator){
230                                                         sidx += group_separator_len-1;
231                                                         state = State_Digits; 
232                                                         break;
233                                                 }
234                                         }
235                                         
236                                         if (Char.IsWhiteSpace (c))
237                                                 goto case State_ConsumeWhiteSpace;
238
239                                         throw new FormatException ("Unknown char: " + c);
240
241                                 case State_Decimal:
242                                         if (Char.IsDigit (c)){
243                                                 b [didx++] = (byte) c;
244                                                 break;
245                                         }
246
247                                         if (c == 'e' || c == 'E'){
248                                                 if ((style & NumberStyles.AllowExponent) == 0)
249                                                         throw new FormatException ("Unknown char: " + c);
250                                                 b [didx++] = (byte) c;
251                                                 state = State_ExponentSign;
252                                                 break;
253                                         }
254                                         
255                                         if (Char.IsWhiteSpace (c))
256                                                 goto case State_ConsumeWhiteSpace;
257                                         throw new FormatException ("Unknown char: " + c);
258
259                                 case State_ExponentSign:
260                                         if (Char.IsDigit (c)){
261                                                 state = State_Exponent;
262                                                 goto case State_Exponent;
263                                         }
264
265                                         if (c == positive [0] &&
266                                             s.Substring (sidx, positive.Length) == positive){
267                                                 state = State_Digits;
268                                                 sidx += positive.Length-1;
269                                                 continue;
270                                         }
271
272                                         if (c == negative [0] &&
273                                             s.Substring (sidx, negative.Length) == negative){
274                                                 state = State_Digits;
275                                                 b [didx++] = (byte) '-';
276                                                 sidx += negative.Length-1;
277                                                 continue;
278                                         }
279
280                                         if (Char.IsWhiteSpace (c))
281                                                 goto case State_ConsumeWhiteSpace;
282                                         
283                                         throw new FormatException ("Unknown char: " + c);
284
285                                 case State_Exponent:
286                                         if (Char.IsDigit (c)){
287                                                 b [didx++] = (byte) c;
288                                                 break;
289                                         }
290                                         
291                                         if (Char.IsWhiteSpace (c))
292                                                 goto case State_ConsumeWhiteSpace;
293                                         throw new FormatException ("Unknown char: " + c);
294
295                                 case State_ConsumeWhiteSpace:
296                                         if (allow_trailing_white && Char.IsWhiteSpace (c))
297                                                 break;
298                                         throw new FormatException ("Unknown char");
299                                 }
300                         }
301
302                         b [didx] = 0;
303                         unsafe {
304                                 fixed (byte *p = &b [0]){
305                                         double retVal = ParseImpl (p);
306                                         if (IsPositiveInfinity(retVal) || IsNegativeInfinity(retVal))
307                                                 throw new OverflowException();
308
309                                         return retVal;
310                                 }
311                         }
312                 }
313
314                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
315                 unsafe private static extern double ParseImpl (byte *byte_ptr);
316                 
317                 public static bool TryParse (string s,
318                                              NumberStyles style,
319                                              IFormatProvider provider,
320                                              out double result)
321                 {
322                         try {
323                                 result = Parse (s, style, provider);
324                                 return true;
325                         } catch {
326                                 result = 0;
327                                 return false;
328                         }
329                 }
330
331                 public override string ToString ()
332                 {
333                         return ToString (null, null);
334                 }
335
336                 public string ToString (IFormatProvider fp)
337                 {
338                         return ToString (null, fp);
339                 }
340
341                 public string ToString (string format)
342                 {
343                         return ToString (format, null);
344                 }
345
346                 public string ToString (string format, IFormatProvider fp)
347                 {
348                         if (fp is CultureInfo)
349                                 return DoubleFormatter.NumberToString(format,
350                                 ((CultureInfo)fp).NumberFormat, m_value);
351                         else
352                                 return DoubleFormatter.NumberToString(format,
353                                 (NumberFormatInfo)fp, m_value);
354                 }
355
356                 // =========== IConvertible Methods =========== //
357
358                 public TypeCode GetTypeCode ()
359                 {
360                         return TypeCode.Double;
361                 }
362
363                 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
364                 {
365                         return System.Convert.ToType(m_value, conversionType, provider);
366                 }
367                 
368                 bool IConvertible.ToBoolean (IFormatProvider provider)
369                 {
370                         return System.Convert.ToBoolean(m_value);
371                 }
372                 
373                 byte IConvertible.ToByte (IFormatProvider provider)
374                 {
375                         return System.Convert.ToByte(m_value);
376                 }
377                 
378                 char IConvertible.ToChar (IFormatProvider provider)
379                 {
380                         throw new InvalidCastException();
381                 }
382                 
383                 DateTime IConvertible.ToDateTime (IFormatProvider provider)
384                 {
385                         throw new InvalidCastException();
386                 }
387                 
388                 decimal IConvertible.ToDecimal (IFormatProvider provider)
389                 {
390                         return System.Convert.ToDecimal(m_value);
391                 }
392                 
393                 double IConvertible.ToDouble (IFormatProvider provider)
394                 {
395                         return System.Convert.ToDouble(m_value);
396                 }
397                 
398                 short IConvertible.ToInt16 (IFormatProvider provider)
399                 {
400                         return System.Convert.ToInt16(m_value);
401                 }
402                 
403                 int IConvertible.ToInt32 (IFormatProvider provider)
404                 {
405                         return System.Convert.ToInt32(m_value);
406                 }
407                 
408                 long IConvertible.ToInt64 (IFormatProvider provider)
409                 {
410                         return System.Convert.ToInt64(m_value);
411                 }
412                 
413                 sbyte IConvertible.ToSByte (IFormatProvider provider)
414                 {
415                         return System.Convert.ToSByte(m_value);
416                 }
417                 
418                 float IConvertible.ToSingle (IFormatProvider provider)
419                 {
420                         return System.Convert.ToSingle(m_value);
421                 }
422                 
423 /*
424                 string IConvertible.ToString (IFormatProvider provider)
425                 {
426                         return ToString(provider);
427                 }
428 */
429
430                 ushort IConvertible.ToUInt16 (IFormatProvider provider)
431                 {
432                         return System.Convert.ToUInt16(m_value);
433                 }
434                 
435                 uint IConvertible.ToUInt32 (IFormatProvider provider)
436                 {
437                         return System.Convert.ToUInt32(m_value);
438                 }
439                 
440                 ulong IConvertible.ToUInt64 (IFormatProvider provider)
441                 {
442                         return System.Convert.ToUInt64(m_value);
443                 }
444         }
445 }