2002-06-04 Nick Drochak <ndrochak@gol.com>
[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                 enum State {
112                         AllowSign, Digits, Decimal, ExponentSign, Exponent, ConsumeWhiteSpace
113                 }
114                 
115                 [MonoTODO("check if digits are group in correct numbers between the group separators")]
116                 public static double Parse (string s, NumberStyles style, IFormatProvider provider)
117                 {
118                         if (s == null) throw new ArgumentNullException();
119                         if (style > NumberStyles.Any)
120                         {
121                                 throw new ArgumentException();
122                         }
123                         NumberFormatInfo format = NumberFormatInfo.GetInstance(provider);
124                         if (format == null) throw new Exception("How did this happen?");
125                         if (s == format.NaNSymbol) return Double.NaN;
126                         if (s == format.PositiveInfinitySymbol) return Double.PositiveInfinity;
127                         if (s == format.NegativeInfinitySymbol) return Double.NegativeInfinity;
128
129                         //
130                         // validate and prepare string for C
131                         //
132                         int len = s.Length;
133                         byte [] b = new byte [len + 1];
134                         int didx = 0;
135                         int sidx = 0;
136                         char c;
137                         
138                         if ((style & NumberStyles.AllowLeadingWhite) != 0){
139                                 while (sidx < len && Char.IsWhiteSpace (c = s [sidx]))
140                                        sidx++;
141
142                                 if (sidx == len)
143                                         throw new FormatException();
144                         }
145
146                         bool allow_trailing_white = ((style & NumberStyles.AllowTrailingWhite) != 0);
147
148                         //
149                         // Machine state
150                         //
151                         State state = State.AllowSign;
152
153                         //
154                         // Setup
155                         //
156                         string decimal_separator = null;
157                         string group_separator = null;
158                         int decimal_separator_len = 0;
159                         int group_separator_len = 0;
160                         if ((style & NumberStyles.AllowDecimalPoint) != 0){
161                                 decimal_separator = format.NumberDecimalSeparator;
162                                 decimal_separator_len = decimal_separator.Length;
163                         }
164                         if ((style & NumberStyles.AllowThousands) != 0){
165                                 group_separator = format.NumberGroupSeparator;
166                                 group_separator_len = group_separator.Length;
167                         }
168                         string positive = format.PositiveSign;
169                         string negative = format.NegativeSign;
170                         
171                         for (; sidx < len; sidx++){
172                                 c = s [sidx];
173
174                                 switch (state){
175                                 case State.AllowSign:
176                                         if ((style & NumberStyles.AllowLeadingSign) != 0){
177                                                 if (c == positive [0] &&
178                                                     s.Substring (sidx, positive.Length) == positive){
179                                                         state = State.Digits;
180                                                         sidx += positive.Length-1;
181                                                         continue;
182                                                 }
183
184                                                 if (c == negative [0] &&
185                                                     s.Substring (sidx, negative.Length) == negative){
186                                                         state = State.Digits;
187                                                         b [didx++] = (byte) '-';
188                                                         sidx += negative.Length-1;
189                                                         continue;
190                                                 }
191                                         }
192                                         state = State.Digits;
193                                         goto case State.Digits;
194                                         
195                                 case State.Digits:
196                                         if (Char.IsDigit (c)){
197                                                 b [didx++] = (byte) c;
198                                                 break;
199                                         }
200                                         if (c == 'e' || c == 'E')
201                                                 goto case State.Decimal;
202                                         
203                                         if (decimal_separator != null &&
204                                             decimal_separator [0] == c){
205                                                 if (s.Substring (sidx, decimal_separator_len) ==
206                                                     decimal_separator){
207                                                         b [didx++] = (byte) '.';
208                                                         sidx += decimal_separator_len-1;
209                                                         state = State.Decimal; 
210                                                         break;
211                                                 }
212                                         }
213                                         if (group_separator != null &&
214                                             group_separator [0] == c){
215                                                 if (s.Substring (sidx, group_separator_len) ==
216                                                     group_separator){
217                                                         sidx += group_separator_len-1;
218                                                         state = State.Digits; 
219                                                         break;
220                                                 }
221                                         }
222                                         
223                                         if (Char.IsWhiteSpace (c))
224                                                 goto case State.ConsumeWhiteSpace;
225
226                                         throw new FormatException ("Unknown char: " + c);
227
228                                 case State.Decimal:
229                                         if (Char.IsDigit (c)){
230                                                 b [didx++] = (byte) c;
231                                                 break;
232                                         }
233
234                                         if (c == 'e' || c == 'E'){
235                                                 if ((style & NumberStyles.AllowExponent) == 0)
236                                                         throw new FormatException ("Unknown char: " + c);
237                                                 b [didx++] = (byte) c;
238                                                 state = State.ExponentSign;
239                                                 break;
240                                         }
241                                         
242                                         if (Char.IsWhiteSpace (c))
243                                                 goto case State.ConsumeWhiteSpace;
244                                         throw new FormatException ("Unknown char: " + c);
245
246                                 case State.ExponentSign:
247                                         if (Char.IsDigit (c)){
248                                                 state = State.Exponent;
249                                                 goto case State.Exponent;
250                                         }
251
252                                         if (c == positive [0] &&
253                                             s.Substring (sidx, positive.Length) == positive){
254                                                 state = State.Digits;
255                                                 sidx += positive.Length-1;
256                                                 continue;
257                                         }
258
259                                         if (c == negative [0] &&
260                                             s.Substring (sidx, negative.Length) == negative){
261                                                 state = State.Digits;
262                                                 b [didx++] = (byte) '-';
263                                                 sidx += negative.Length-1;
264                                                 continue;
265                                         }
266
267                                         if (Char.IsWhiteSpace (c))
268                                                 goto case State.ConsumeWhiteSpace;
269                                         
270                                         throw new FormatException ("Unknown char: " + c);
271
272                                 case State.Exponent:
273                                         if (Char.IsDigit (c)){
274                                                 b [didx++] = (byte) c;
275                                                 break;
276                                         }
277                                         
278                                         if (Char.IsWhiteSpace (c))
279                                                 goto case State.ConsumeWhiteSpace;
280                                         throw new FormatException ("Unknown char: " + c);
281
282                                 case State.ConsumeWhiteSpace:
283                                         if (allow_trailing_white && Char.IsWhiteSpace (c))
284                                                 break;
285                                         throw new FormatException ("Unknown char");
286                                 }
287                         }
288
289                         b [didx] = 0;
290                         unsafe {
291                                 fixed (byte *p = &b [0]){
292                                         double retVal = ParseImpl (p);
293                                         if (IsPositiveInfinity(retVal) || IsNegativeInfinity(retVal))
294                                                 throw new OverflowException();
295
296                                         return retVal;
297                                 }
298                         }
299                 }
300
301                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
302                 unsafe private static extern double ParseImpl (byte *byte_ptr);
303                 
304                 public override string ToString ()
305                 {
306                         return ToString (null, null);
307                 }
308
309                 public string ToString (IFormatProvider fp)
310                 {
311                         return ToString (null, fp);
312                 }
313
314                 public string ToString (string format)
315                 {
316                         return ToString (format, null);
317                 }
318
319                 [MonoTODO]
320                 public string ToString (string format, IFormatProvider fp)
321                 {
322                         // FIXME: Need to pass format and provider info to this call too.
323                         return ToStringImpl(value);
324                 }
325
326                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
327                 private static extern string ToStringImpl (double value);
328
329                 // =========== IConvertible Methods =========== //
330
331                 public TypeCode GetTypeCode ()
332                 {
333                         return TypeCode.Double;
334                 }
335
336                 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
337                 {
338                         return System.Convert.ToType(value, conversionType, provider);
339                 }
340                 
341                 bool IConvertible.ToBoolean (IFormatProvider provider)
342                 {
343                         return System.Convert.ToBoolean(value);
344                 }
345                 
346                 byte IConvertible.ToByte (IFormatProvider provider)
347                 {
348                         return System.Convert.ToByte(value);
349                 }
350                 
351                 char IConvertible.ToChar (IFormatProvider provider)
352                 {
353                         throw new InvalidCastException();
354                 }
355                 
356                 [CLSCompliant(false)]
357                 DateTime IConvertible.ToDateTime (IFormatProvider provider)
358                 {
359                         throw new InvalidCastException();
360                 }
361                 
362                 decimal IConvertible.ToDecimal (IFormatProvider provider)
363                 {
364                         return System.Convert.ToDecimal(value);
365                 }
366                 
367                 double IConvertible.ToDouble (IFormatProvider provider)
368                 {
369                         return System.Convert.ToDouble(value);
370                 }
371                 
372                 short IConvertible.ToInt16 (IFormatProvider provider)
373                 {
374                         return System.Convert.ToInt16(value);
375                 }
376                 
377                 int IConvertible.ToInt32 (IFormatProvider provider)
378                 {
379                         return System.Convert.ToInt32(value);
380                 }
381                 
382                 long IConvertible.ToInt64 (IFormatProvider provider)
383                 {
384                         return System.Convert.ToInt64(value);
385                 }
386                 
387                 [CLSCompliant(false)] 
388                 sbyte IConvertible.ToSByte (IFormatProvider provider)
389                 {
390                         return System.Convert.ToSByte(value);
391                 }
392                 
393                 float IConvertible.ToSingle (IFormatProvider provider)
394                 {
395                         return System.Convert.ToSingle(value);
396                 }
397                 
398 /*
399                 string IConvertible.ToString (IFormatProvider provider)
400                 {
401                         return ToString(provider);
402                 }
403 */
404
405                 [CLSCompliant(false)]
406                 ushort IConvertible.ToUInt16 (IFormatProvider provider)
407                 {
408                         return System.Convert.ToUInt16(value);
409                 }
410                 
411                 [CLSCompliant(false)]
412                 uint IConvertible.ToUInt32 (IFormatProvider provider)
413                 {
414                         return System.Convert.ToUInt32(value);
415                 }
416                 
417                 [CLSCompliant(false)]
418                 ulong IConvertible.ToUInt64 (IFormatProvider provider)
419                 {
420                         return System.Convert.ToUInt64(value);
421                 }
422         }
423 }