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