* Mono.Posix.dll.sources: Rename Mono.Posix to Mono.Unix.
[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 unsafe int GetHashCode ()
103                 {
104                         double d = m_value;
105                         return (*((long*)&d)).GetHashCode ();
106                 }
107
108                 public static bool IsInfinity (double d)
109                 {
110                         return (d == PositiveInfinity || d == NegativeInfinity);
111                 }
112
113                 public static bool IsNaN (double d)
114                 {
115                         return (d != d);
116                 }
117
118                 public static bool IsNegativeInfinity (double d)
119                 {
120                         return (d < 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
121                 }
122
123                 public static bool IsPositiveInfinity (double d)
124                 {
125                         return (d > 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
126                 }
127
128                 public static double Parse (string s)
129                 {
130                         return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), null);
131                 }
132
133                 public static double Parse (string s, IFormatProvider fp)
134                 {
135                         return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), fp);
136                 }
137
138                 public static double Parse (string s, NumberStyles style) 
139                 {
140                         return Parse (s, style, null);
141                 }
142
143                 // We're intentionally using constants here to avoid some bigger headaches in mcs.
144                 // This struct must be compiled before System.Enum so we can't use enums here.
145                 private const int State_AllowSign = 1;
146                 private const int State_Digits = 2;
147                 private const int State_Decimal = 3;
148                 private const int State_ExponentSign = 4;
149                 private const int State_Exponent = 5;
150                 private const int State_ConsumeWhiteSpace = 6;
151                 
152                 [MonoTODO("check if digits are group in correct numbers between the group separators")]
153                 public static double Parse (string s, NumberStyles style, IFormatProvider provider)
154                 {
155                         if (s == null) throw new ArgumentNullException();
156                         if (style > NumberStyles.Any)
157                         {
158                                 throw new ArgumentException();
159                         }
160                         NumberFormatInfo format = NumberFormatInfo.GetInstance(provider);
161                         if (format == null) throw new Exception("How did this happen?");
162                         if (s == format.NaNSymbol) return Double.NaN;
163                         if (s == format.PositiveInfinitySymbol) return Double.PositiveInfinity;
164                         if (s == format.NegativeInfinitySymbol) return Double.NegativeInfinity;
165
166                         //
167                         // validate and prepare string for C
168                         //
169                         int len = s.Length;
170                         byte [] b = new byte [len + 1];
171                         int didx = 0;
172                         int sidx = 0;
173                         char c;
174                         
175                         if ((style & NumberStyles.AllowLeadingWhite) != 0){
176                                 while (sidx < len && Char.IsWhiteSpace (c = s [sidx]))
177                                        sidx++;
178
179                                 if (sidx == len)
180                                         throw new FormatException();
181                         }
182
183                         bool allow_trailing_white = ((style & NumberStyles.AllowTrailingWhite) != 0);
184
185                         //
186                         // Machine state
187                         //
188                         int state = State_AllowSign;
189
190                         //
191                         // Setup
192                         //
193                         string decimal_separator = null;
194                         string group_separator = null;
195                         int decimal_separator_len = 0;
196                         int group_separator_len = 0;
197                         if ((style & NumberStyles.AllowDecimalPoint) != 0){
198                                 decimal_separator = format.NumberDecimalSeparator;
199                                 decimal_separator_len = decimal_separator.Length;
200                         }
201                         if ((style & NumberStyles.AllowThousands) != 0){
202                                 group_separator = format.NumberGroupSeparator;
203                                 group_separator_len = group_separator.Length;
204                         }
205                         string positive = format.PositiveSign;
206                         string negative = format.NegativeSign;
207                         
208                         for (; sidx < len; sidx++){
209                                 c = s [sidx];
210
211                                 if (c == '\0') {
212                                         sidx = len;
213                                         continue;
214                                 }
215                                 switch (state){
216                                 case State_AllowSign:
217                                         if ((style & NumberStyles.AllowLeadingSign) != 0){
218                                                 if (c == positive [0] &&
219                                                     s.Substring (sidx, positive.Length) == positive){
220                                                         state = State_Digits;
221                                                         sidx += positive.Length-1;
222                                                         continue;
223                                                 }
224
225                                                 if (c == negative [0] &&
226                                                     s.Substring (sidx, negative.Length) == negative){
227                                                         state = State_Digits;
228                                                         b [didx++] = (byte) '-';
229                                                         sidx += negative.Length-1;
230                                                         continue;
231                                                 }
232                                         }
233                                         state = State_Digits;
234                                         goto case State_Digits;
235                                         
236                                 case State_Digits:
237                                         if (Char.IsDigit (c)){
238                                                 b [didx++] = (byte) c;
239                                                 break;
240                                         }
241                                         if (c == 'e' || c == 'E')
242                                                 goto case State_Decimal;
243                                         
244                                         if (decimal_separator != null &&
245                                             decimal_separator [0] == c){
246                                                 if (s.Substring (sidx, decimal_separator_len) ==
247                                                     decimal_separator){
248                                                         b [didx++] = (byte) '.';
249                                                         sidx += decimal_separator_len-1;
250                                                         state = State_Decimal; 
251                                                         break;
252                                                 }
253                                         }
254                                         if (group_separator != null &&
255                                             group_separator [0] == c){
256                                                 if (s.Substring (sidx, group_separator_len) ==
257                                                     group_separator){
258                                                         sidx += group_separator_len-1;
259                                                         state = State_Digits; 
260                                                         break;
261                                                 }
262                                         }
263                                         
264                                         if (Char.IsWhiteSpace (c))
265                                                 goto case State_ConsumeWhiteSpace;
266
267                                         throw new FormatException ("Unknown char: " + c);
268
269                                 case State_Decimal:
270                                         if (Char.IsDigit (c)){
271                                                 b [didx++] = (byte) c;
272                                                 break;
273                                         }
274
275                                         if (c == 'e' || c == 'E'){
276                                                 if ((style & NumberStyles.AllowExponent) == 0)
277                                                         throw new FormatException ("Unknown char: " + c);
278                                                 b [didx++] = (byte) c;
279                                                 state = State_ExponentSign;
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_ExponentSign:
288                                         if (Char.IsDigit (c)){
289                                                 state = State_Exponent;
290                                                 goto case State_Exponent;
291                                         }
292
293                                         if (c == positive [0] &&
294                                             s.Substring (sidx, positive.Length) == positive){
295                                                 state = State_Digits;
296                                                 sidx += positive.Length-1;
297                                                 continue;
298                                         }
299
300                                         if (c == negative [0] &&
301                                             s.Substring (sidx, negative.Length) == negative){
302                                                 state = State_Digits;
303                                                 b [didx++] = (byte) '-';
304                                                 sidx += negative.Length-1;
305                                                 continue;
306                                         }
307
308                                         if (Char.IsWhiteSpace (c))
309                                                 goto case State_ConsumeWhiteSpace;
310                                         
311                                         throw new FormatException ("Unknown char: " + c);
312
313                                 case State_Exponent:
314                                         if (Char.IsDigit (c)){
315                                                 b [didx++] = (byte) c;
316                                                 break;
317                                         }
318                                         
319                                         if (Char.IsWhiteSpace (c))
320                                                 goto case State_ConsumeWhiteSpace;
321                                         throw new FormatException ("Unknown char: " + c);
322
323                                 case State_ConsumeWhiteSpace:
324                                         if (allow_trailing_white && Char.IsWhiteSpace (c))
325                                                 break;
326                                         throw new FormatException ("Unknown char");
327                                 }
328                         }
329
330                         b [didx] = 0;
331                         unsafe {
332                                 fixed (byte *p = &b [0]){
333                                         double retVal = ParseImpl (p);
334                                         if (IsPositiveInfinity(retVal) || IsNegativeInfinity(retVal))
335                                                 throw new OverflowException();
336
337                                         return retVal;
338                                 }
339                         }
340                 }
341
342                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
343                 unsafe private static extern double ParseImpl (byte *byte_ptr);
344                 
345                 public static bool TryParse (string s,
346                                              NumberStyles style,
347                                              IFormatProvider provider,
348                                              out double result)
349                 {
350                         try {
351                                 result = Parse (s, style, provider);
352                                 return true;
353                         } catch {
354                                 result = 0;
355                                 return false;
356                         }
357                 }
358
359                 public override string ToString ()
360                 {
361                         return ToString (null, null);
362                 }
363
364                 public string ToString (IFormatProvider fp)
365                 {
366                         return ToString (null, fp);
367                 }
368
369                 public string ToString (string format)
370                 {
371                         return ToString (format, null);
372                 }
373
374                 public string ToString (string format, IFormatProvider fp)
375                 {
376                         NumberFormatInfo nfi = fp != null ? fp.GetFormat (typeof (NumberFormatInfo)) as NumberFormatInfo : null;
377                         return DoubleFormatter.NumberToString (format, nfi, m_value);
378                 }
379
380                 // =========== IConvertible Methods =========== //
381
382                 public TypeCode GetTypeCode ()
383                 {
384                         return TypeCode.Double;
385                 }
386
387                 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
388                 {
389                         return System.Convert.ToType(m_value, conversionType, provider);
390                 }
391                 
392                 bool IConvertible.ToBoolean (IFormatProvider provider)
393                 {
394                         return System.Convert.ToBoolean(m_value);
395                 }
396                 
397                 byte IConvertible.ToByte (IFormatProvider provider)
398                 {
399                         return System.Convert.ToByte(m_value);
400                 }
401                 
402                 char IConvertible.ToChar (IFormatProvider provider)
403                 {
404                         throw new InvalidCastException();
405                 }
406                 
407                 DateTime IConvertible.ToDateTime (IFormatProvider provider)
408                 {
409                         throw new InvalidCastException();
410                 }
411                 
412                 decimal IConvertible.ToDecimal (IFormatProvider provider)
413                 {
414                         return System.Convert.ToDecimal(m_value);
415                 }
416                 
417                 double IConvertible.ToDouble (IFormatProvider provider)
418                 {
419                         return System.Convert.ToDouble(m_value);
420                 }
421                 
422                 short IConvertible.ToInt16 (IFormatProvider provider)
423                 {
424                         return System.Convert.ToInt16(m_value);
425                 }
426                 
427                 int IConvertible.ToInt32 (IFormatProvider provider)
428                 {
429                         return System.Convert.ToInt32(m_value);
430                 }
431                 
432                 long IConvertible.ToInt64 (IFormatProvider provider)
433                 {
434                         return System.Convert.ToInt64(m_value);
435                 }
436                 
437                 sbyte IConvertible.ToSByte (IFormatProvider provider)
438                 {
439                         return System.Convert.ToSByte(m_value);
440                 }
441                 
442                 float IConvertible.ToSingle (IFormatProvider provider)
443                 {
444                         return System.Convert.ToSingle(m_value);
445                 }
446                 
447 /*
448                 string IConvertible.ToString (IFormatProvider provider)
449                 {
450                         return ToString(provider);
451                 }
452 */
453
454                 ushort IConvertible.ToUInt16 (IFormatProvider provider)
455                 {
456                         return System.Convert.ToUInt16(m_value);
457                 }
458                 
459                 uint IConvertible.ToUInt32 (IFormatProvider provider)
460                 {
461                         return System.Convert.ToUInt32(m_value);
462                 }
463                 
464                 ulong IConvertible.ToUInt64 (IFormatProvider provider)
465                 {
466                         return System.Convert.ToUInt64(m_value);
467                 }
468         }
469 }