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