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