2002-05-13 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 (decimal_separator != null &&
194                                             decimal_separator [0] == c){
195                                                 if (s.Substring (sidx, decimal_separator_len) ==
196                                                     decimal_separator){
197                                                         b [didx++] = (byte) '.';
198                                                         sidx += decimal_separator_len-1;
199                                                         state = State.Decimal; 
200                                                         break;
201                                                 }
202                                         }
203                                         
204                                         if (Char.IsWhiteSpace (c))
205                                                 goto case State.ConsumeWhiteSpace;
206
207                                         throw new FormatException ("Unknown char: " + c);
208
209                                 case State.Decimal:
210                                         if (Char.IsDigit (c)){
211                                                 b [didx++] = (byte) c;
212                                                 break;
213                                         }
214
215                                         if (c == 'e' || c == 'E'){
216                                                 if ((style & NumberStyles.AllowExponent) == 0)
217                                                         throw new FormatException ("Unknown char: " + c);
218                                                 b [didx++] = (byte) c;
219                                                 state = State.ExponentSign;
220                                                 break;
221                                         }
222                                         
223                                         if (Char.IsWhiteSpace (c))
224                                                 goto case State.ConsumeWhiteSpace;
225                                         throw new FormatException ("Unknown char: " + c);
226
227                                 case State.ExponentSign:
228                                         if (Char.IsDigit (c)){
229                                                 state = State.Exponent;
230                                                 goto case State.Exponent;
231                                         }
232
233                                         if (c == positive [0] &&
234                                             s.Substring (sidx, positive.Length) == positive){
235                                                 state = State.Digits;
236                                                 sidx += positive.Length-1;
237                                                 continue;
238                                         }
239
240                                         if (c == negative [0] &&
241                                             s.Substring (sidx, negative.Length) == negative){
242                                                 state = State.Digits;
243                                                 b [didx++] = (byte) '-';
244                                                 sidx += negative.Length-1;
245                                                 continue;
246                                         }
247
248                                         if (Char.IsWhiteSpace (c))
249                                                 goto case State.ConsumeWhiteSpace;
250                                         
251                                         throw new FormatException ("Unknown char: " + c);
252
253                                 case State.Exponent:
254                                         if (Char.IsDigit (c)){
255                                                 b [didx++] = (byte) c;
256                                                 break;
257                                         }
258                                         
259                                         if (Char.IsWhiteSpace (c))
260                                                 goto case State.ConsumeWhiteSpace;
261                                         throw new FormatException ("Unknown char: " + c);
262
263                                 case State.ConsumeWhiteSpace:
264                                         if (allow_trailing_white && Char.IsWhiteSpace (c))
265                                                 break;
266                                         throw new FormatException ("Unknown char");
267                                 }
268                         }
269
270                         b [didx] = 0;
271                         unsafe {
272                                 fixed (byte *p = &b [0]){
273                                         return ParseImpl (p);
274                                 }
275                         }
276                 }
277
278                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
279                 unsafe private static extern double ParseImpl (byte *byte_ptr);
280                 
281                 public override string ToString ()
282                 {
283                         return ToString (null, null);
284                 }
285
286                 public string ToString (IFormatProvider fp)
287                 {
288                         return ToString (null, fp);
289                 }
290
291                 public string ToString (string format)
292                 {
293                         return ToString (format, null);
294                 }
295
296                 [MonoTODO]
297                 public string ToString (string format, IFormatProvider fp)
298                 {
299                         // FIXME: Need to pass format and provider info to this call too.
300                         return ToStringImpl(value);
301                 }
302
303                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
304                 private static extern string ToStringImpl (double value);
305
306                 // =========== IConvertible Methods =========== //
307
308                 public TypeCode GetTypeCode ()
309                 {
310                         return TypeCode.Double;
311                 }
312
313                 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
314                 {
315                         return System.Convert.ToType(value, conversionType, provider);
316                 }
317                 
318                 bool IConvertible.ToBoolean (IFormatProvider provider)
319                 {
320                         return System.Convert.ToBoolean(value);
321                 }
322                 
323                 byte IConvertible.ToByte (IFormatProvider provider)
324                 {
325                         return System.Convert.ToByte(value);
326                 }
327                 
328                 char IConvertible.ToChar (IFormatProvider provider)
329                 {
330                         throw new InvalidCastException();
331                 }
332                 
333                 [CLSCompliant(false)]
334                 DateTime IConvertible.ToDateTime (IFormatProvider provider)
335                 {
336                         throw new InvalidCastException();
337                 }
338                 
339                 decimal IConvertible.ToDecimal (IFormatProvider provider)
340                 {
341                         return System.Convert.ToDecimal(value);
342                 }
343                 
344                 double IConvertible.ToDouble (IFormatProvider provider)
345                 {
346                         return System.Convert.ToDouble(value);
347                 }
348                 
349                 short IConvertible.ToInt16 (IFormatProvider provider)
350                 {
351                         return System.Convert.ToInt16(value);
352                 }
353                 
354                 int IConvertible.ToInt32 (IFormatProvider provider)
355                 {
356                         return System.Convert.ToInt32(value);
357                 }
358                 
359                 long IConvertible.ToInt64 (IFormatProvider provider)
360                 {
361                         return System.Convert.ToInt64(value);
362                 }
363                 
364                 [CLSCompliant(false)] 
365                 sbyte IConvertible.ToSByte (IFormatProvider provider)
366                 {
367                         return System.Convert.ToSByte(value);
368                 }
369                 
370                 float IConvertible.ToSingle (IFormatProvider provider)
371                 {
372                         return System.Convert.ToSingle(value);
373                 }
374                 
375 /*
376                 string IConvertible.ToString (IFormatProvider provider)
377                 {
378                         return ToString(provider);
379                 }
380 */
381
382                 [CLSCompliant(false)]
383                 ushort IConvertible.ToUInt16 (IFormatProvider provider)
384                 {
385                         return System.Convert.ToUInt16(value);
386                 }
387                 
388                 [CLSCompliant(false)]
389                 uint IConvertible.ToUInt32 (IFormatProvider provider)
390                 {
391                         return System.Convert.ToUInt32(value);
392                 }
393                 
394                 [CLSCompliant(false)]
395                 ulong IConvertible.ToUInt64 (IFormatProvider provider)
396                 {
397                         return System.Convert.ToUInt64(value);
398                 }
399         }
400 }