This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[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 //
13 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 //
34
35 using System.Globalization;
36 using System.Runtime.CompilerServices;
37
38 namespace System {
39         
40         [Serializable]
41         public struct Double : IComparable, IFormattable, IConvertible {
42                 public const double Epsilon = 4.9406564584124650e-324;
43                 public const double MaxValue =  1.7976931348623157e308;
44                 public const double MinValue = -1.7976931348623157e308;
45                 public const double NaN = 0.0d / 0.0d;
46                 public const double NegativeInfinity = -1.0d / 0.0d;
47                 public const double PositiveInfinity = 1.0d / 0.0d;
48                 
49                 internal double m_value;
50
51                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
52                 extern internal static void AssertEndianity (out double value);
53
54                 public int CompareTo (object v)
55                 {
56                         if (v == null)
57                                 return 1;
58                         
59                         if (!(v is System.Double))
60                                 throw new ArgumentException (Locale.GetText ("Value is not a System.Double"));
61
62                         double dv = (double)v;
63
64                         if (IsPositiveInfinity(m_value) && IsPositiveInfinity(dv))
65                                 return 0;
66
67                         if (IsNegativeInfinity(m_value) && IsNegativeInfinity(dv))
68                                 return 0;
69
70                         if (IsNaN(dv))
71                                 if (IsNaN(m_value))
72                                         return 0;
73                                 else
74                                         return 1;
75
76                         if (IsNaN(m_value))
77                                 if (IsNaN(dv))
78                                         return 0;
79                                 else
80                                         return -1;
81
82                         if (m_value > dv) return 1;
83                         else if (m_value < dv) return -1;
84                         else return 0;
85                 }
86
87                 public override bool Equals (object o)
88                 {
89                         if (!(o is System.Double))
90                                 return false;
91
92                         if (IsNaN ((double)o)) {
93                                 if (IsNaN(m_value))
94                                         return true;
95                                 else
96                                         return false;
97                         }
98
99                         return ((double) o) == m_value;
100                 }
101
102                 public override int GetHashCode ()
103                 {
104                         return (int) m_value;
105                 }
106
107                 public static bool IsInfinity (double d)
108                 {
109                         return (d == PositiveInfinity || d == NegativeInfinity);
110                 }
111
112                 public static bool IsNaN (double d)
113                 {
114                         return (d != d);
115                 }
116
117                 public static bool IsNegativeInfinity (double d)
118                 {
119                         return (d < 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
120                 }
121
122                 public static bool IsPositiveInfinity (double d)
123                 {
124                         return (d > 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
125                 }
126
127                 public static double Parse (string s)
128                 {
129                         return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), null);
130                 }
131
132                 public static double Parse (string s, IFormatProvider fp)
133                 {
134                         return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), fp);
135                 }
136
137                 public static double Parse (string s, NumberStyles style) 
138                 {
139                         return Parse (s, style, null);
140                 }
141
142                 // We're intentionally using constants here to avoid some bigger headaches in mcs.
143                 // This struct must be compiled before System.Enum so we can't use enums here.
144                 private const int State_AllowSign = 1;
145                 private const int State_Digits = 2;
146                 private const int State_Decimal = 3;
147                 private const int State_ExponentSign = 4;
148                 private const int State_Exponent = 5;
149                 private const int State_ConsumeWhiteSpace = 6;
150                 
151                 [MonoTODO("check if digits are group in correct numbers between the group separators")]
152                 public static double Parse (string s, NumberStyles style, IFormatProvider provider)
153                 {
154                         if (s == null) throw new ArgumentNullException();
155                         if (style > NumberStyles.Any)
156                         {
157                                 throw new ArgumentException();
158                         }
159                         NumberFormatInfo format = NumberFormatInfo.GetInstance(provider);
160                         if (format == null) throw new Exception("How did this happen?");
161                         if (s == format.NaNSymbol) return Double.NaN;
162                         if (s == format.PositiveInfinitySymbol) return Double.PositiveInfinity;
163                         if (s == format.NegativeInfinitySymbol) return Double.NegativeInfinity;
164
165                         //
166                         // validate and prepare string for C
167                         //
168                         int len = s.Length;
169                         byte [] b = new byte [len + 1];
170                         int didx = 0;
171                         int sidx = 0;
172                         char c;
173                         
174                         if ((style & NumberStyles.AllowLeadingWhite) != 0){
175                                 while (sidx < len && Char.IsWhiteSpace (c = s [sidx]))
176                                        sidx++;
177
178                                 if (sidx == len)
179                                         throw new FormatException();
180                         }
181
182                         bool allow_trailing_white = ((style & NumberStyles.AllowTrailingWhite) != 0);
183
184                         //
185                         // Machine state
186                         //
187                         int state = State_AllowSign;
188
189                         //
190                         // Setup
191                         //
192                         string decimal_separator = null;
193                         string group_separator = null;
194                         int decimal_separator_len = 0;
195                         int group_separator_len = 0;
196                         if ((style & NumberStyles.AllowDecimalPoint) != 0){
197                                 decimal_separator = format.NumberDecimalSeparator;
198                                 decimal_separator_len = decimal_separator.Length;
199                         }
200                         if ((style & NumberStyles.AllowThousands) != 0){
201                                 group_separator = format.NumberGroupSeparator;
202                                 group_separator_len = group_separator.Length;
203                         }
204                         string positive = format.PositiveSign;
205                         string negative = format.NegativeSign;
206                         
207                         for (; sidx < len; sidx++){
208                                 c = s [sidx];
209
210                                 if (c == '\0') {
211                                         sidx = len;
212                                         continue;
213                                 }
214                                 switch (state){
215                                 case State_AllowSign:
216                                         if ((style & NumberStyles.AllowLeadingSign) != 0){
217                                                 if (c == positive [0] &&
218                                                     s.Substring (sidx, positive.Length) == positive){
219                                                         state = State_Digits;
220                                                         sidx += positive.Length-1;
221                                                         continue;
222                                                 }
223
224                                                 if (c == negative [0] &&
225                                                     s.Substring (sidx, negative.Length) == negative){
226                                                         state = State_Digits;
227                                                         b [didx++] = (byte) '-';
228                                                         sidx += negative.Length-1;
229                                                         continue;
230                                                 }
231                                         }
232                                         state = State_Digits;
233                                         goto case State_Digits;
234                                         
235                                 case State_Digits:
236                                         if (Char.IsDigit (c)){
237                                                 b [didx++] = (byte) c;
238                                                 break;
239                                         }
240                                         if (c == 'e' || c == 'E')
241                                                 goto case State_Decimal;
242                                         
243                                         if (decimal_separator != null &&
244                                             decimal_separator [0] == c){
245                                                 if (s.Substring (sidx, decimal_separator_len) ==
246                                                     decimal_separator){
247                                                         b [didx++] = (byte) '.';
248                                                         sidx += decimal_separator_len-1;
249                                                         state = State_Decimal; 
250                                                         break;
251                                                 }
252                                         }
253                                         if (group_separator != null &&
254                                             group_separator [0] == c){
255                                                 if (s.Substring (sidx, group_separator_len) ==
256                                                     group_separator){
257                                                         sidx += group_separator_len-1;
258                                                         state = State_Digits; 
259                                                         break;
260                                                 }
261                                         }
262                                         
263                                         if (Char.IsWhiteSpace (c))
264                                                 goto case State_ConsumeWhiteSpace;
265
266                                         throw new FormatException ("Unknown char: " + c);
267
268                                 case State_Decimal:
269                                         if (Char.IsDigit (c)){
270                                                 b [didx++] = (byte) c;
271                                                 break;
272                                         }
273
274                                         if (c == 'e' || c == 'E'){
275                                                 if ((style & NumberStyles.AllowExponent) == 0)
276                                                         throw new FormatException ("Unknown char: " + c);
277                                                 b [didx++] = (byte) c;
278                                                 state = State_ExponentSign;
279                                                 break;
280                                         }
281                                         
282                                         if (Char.IsWhiteSpace (c))
283                                                 goto case State_ConsumeWhiteSpace;
284                                         throw new FormatException ("Unknown char: " + c);
285
286                                 case State_ExponentSign:
287                                         if (Char.IsDigit (c)){
288                                                 state = State_Exponent;
289                                                 goto case State_Exponent;
290                                         }
291
292                                         if (c == positive [0] &&
293                                             s.Substring (sidx, positive.Length) == positive){
294                                                 state = State_Digits;
295                                                 sidx += positive.Length-1;
296                                                 continue;
297                                         }
298
299                                         if (c == negative [0] &&
300                                             s.Substring (sidx, negative.Length) == negative){
301                                                 state = State_Digits;
302                                                 b [didx++] = (byte) '-';
303                                                 sidx += negative.Length-1;
304                                                 continue;
305                                         }
306
307                                         if (Char.IsWhiteSpace (c))
308                                                 goto case State_ConsumeWhiteSpace;
309                                         
310                                         throw new FormatException ("Unknown char: " + c);
311
312                                 case State_Exponent:
313                                         if (Char.IsDigit (c)){
314                                                 b [didx++] = (byte) c;
315                                                 break;
316                                         }
317                                         
318                                         if (Char.IsWhiteSpace (c))
319                                                 goto case State_ConsumeWhiteSpace;
320                                         throw new FormatException ("Unknown char: " + c);
321
322                                 case State_ConsumeWhiteSpace:
323                                         if (allow_trailing_white && Char.IsWhiteSpace (c))
324                                                 break;
325                                         throw new FormatException ("Unknown char");
326                                 }
327                         }
328
329                         b [didx] = 0;
330                         unsafe {
331                                 fixed (byte *p = &b [0]){
332                                         double retVal = ParseImpl (p);
333                                         if (IsPositiveInfinity(retVal) || IsNegativeInfinity(retVal))
334                                                 throw new OverflowException();
335
336                                         return retVal;
337                                 }
338                         }
339                 }
340
341                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
342                 unsafe private static extern double ParseImpl (byte *byte_ptr);
343                 
344                 public static bool TryParse (string s,
345                                              NumberStyles style,
346                                              IFormatProvider provider,
347                                              out double result)
348                 {
349                         try {
350                                 result = Parse (s, style, provider);
351                                 return true;
352                         } catch {
353                                 result = 0;
354                                 return false;
355                         }
356                 }
357
358                 public override string ToString ()
359                 {
360                         return ToString (null, null);
361                 }
362
363                 public string ToString (IFormatProvider fp)
364                 {
365                         return ToString (null, fp);
366                 }
367
368                 public string ToString (string format)
369                 {
370                         return ToString (format, null);
371                 }
372
373                 public string ToString (string format, IFormatProvider fp)
374                 {
375                         NumberFormatInfo nfi = fp != null ? fp.GetFormat (typeof (NumberFormatInfo)) as NumberFormatInfo : null;
376                         return DoubleFormatter.NumberToString (format, nfi, m_value);
377                 }
378
379                 // =========== IConvertible Methods =========== //
380
381                 public TypeCode GetTypeCode ()
382                 {
383                         return TypeCode.Double;
384                 }
385
386                 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
387                 {
388                         return System.Convert.ToType(m_value, conversionType, provider);
389                 }
390                 
391                 bool IConvertible.ToBoolean (IFormatProvider provider)
392                 {
393                         return System.Convert.ToBoolean(m_value);
394                 }
395                 
396                 byte IConvertible.ToByte (IFormatProvider provider)
397                 {
398                         return System.Convert.ToByte(m_value);
399                 }
400                 
401                 char IConvertible.ToChar (IFormatProvider provider)
402                 {
403                         throw new InvalidCastException();
404                 }
405                 
406                 DateTime IConvertible.ToDateTime (IFormatProvider provider)
407                 {
408                         throw new InvalidCastException();
409                 }
410                 
411                 decimal IConvertible.ToDecimal (IFormatProvider provider)
412                 {
413                         return System.Convert.ToDecimal(m_value);
414                 }
415                 
416                 double IConvertible.ToDouble (IFormatProvider provider)
417                 {
418                         return System.Convert.ToDouble(m_value);
419                 }
420                 
421                 short IConvertible.ToInt16 (IFormatProvider provider)
422                 {
423                         return System.Convert.ToInt16(m_value);
424                 }
425                 
426                 int IConvertible.ToInt32 (IFormatProvider provider)
427                 {
428                         return System.Convert.ToInt32(m_value);
429                 }
430                 
431                 long IConvertible.ToInt64 (IFormatProvider provider)
432                 {
433                         return System.Convert.ToInt64(m_value);
434                 }
435                 
436                 sbyte IConvertible.ToSByte (IFormatProvider provider)
437                 {
438                         return System.Convert.ToSByte(m_value);
439                 }
440                 
441                 float IConvertible.ToSingle (IFormatProvider provider)
442                 {
443                         return System.Convert.ToSingle(m_value);
444                 }
445                 
446 /*
447                 string IConvertible.ToString (IFormatProvider provider)
448                 {
449                         return ToString(provider);
450                 }
451 */
452
453                 ushort IConvertible.ToUInt16 (IFormatProvider provider)
454                 {
455                         return System.Convert.ToUInt16(m_value);
456                 }
457                 
458                 uint IConvertible.ToUInt32 (IFormatProvider provider)
459                 {
460                         return System.Convert.ToUInt32(m_value);
461                 }
462                 
463                 ulong IConvertible.ToUInt64 (IFormatProvider provider)
464                 {
465                         return System.Convert.ToUInt64(m_value);
466                 }
467         }
468 }