merge -r 58060:58217
[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 #if NET_2_0
39 using System.Runtime.ConstrainedExecution;
40 #endif
41
42 namespace System {
43         
44         [Serializable]
45         public struct Double : IComparable, IFormattable, IConvertible
46 #if NET_2_0
47                 , IComparable <double>, IEquatable <double>
48 #endif
49         {
50                 public const double Epsilon = 4.9406564584124650e-324;
51                 public const double MaxValue =  1.7976931348623157e308;
52                 public const double MinValue = -1.7976931348623157e308;
53                 public const double NaN = 0.0d / 0.0d;
54                 public const double NegativeInfinity = -1.0d / 0.0d;
55                 public const double PositiveInfinity = 1.0d / 0.0d;
56                 
57                 internal double m_value;
58
59                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
60                 extern internal static void AssertEndianity (out double value);
61
62                 public int CompareTo (object v)
63                 {
64                         if (v == null)
65                                 return 1;
66                         
67                         if (!(v is System.Double))
68                                 throw new ArgumentException (Locale.GetText ("Value is not a System.Double"));
69
70                         double dv = (double)v;
71
72                         if (IsPositiveInfinity(m_value) && IsPositiveInfinity(dv))
73                                 return 0;
74
75                         if (IsNegativeInfinity(m_value) && IsNegativeInfinity(dv))
76                                 return 0;
77
78                         if (IsNaN(dv))
79                                 if (IsNaN(m_value))
80                                         return 0;
81                                 else
82                                         return 1;
83
84                         if (IsNaN(m_value))
85                                 if (IsNaN(dv))
86                                         return 0;
87                                 else
88                                         return -1;
89
90                         if (m_value > dv) return 1;
91                         else if (m_value < dv) return -1;
92                         else return 0;
93                 }
94
95                 public override bool Equals (object o)
96                 {
97                         if (!(o is System.Double))
98                                 return false;
99
100                         if (IsNaN ((double)o)) {
101                                 if (IsNaN(m_value))
102                                         return true;
103                                 else
104                                         return false;
105                         }
106
107                         return ((double) o) == m_value;
108                 }
109
110 #if NET_2_0
111                 public int CompareTo (double value)
112                 {
113                         if (IsPositiveInfinity(m_value) && IsPositiveInfinity(value))
114                                 return 0;
115
116                         if (IsNegativeInfinity(m_value) && IsNegativeInfinity(value))
117                                 return 0;
118
119                         if (IsNaN(value))
120                                 if (IsNaN(m_value))
121                                         return 0;
122                                 else
123                                         return 1;
124
125                         if (IsNaN(m_value))
126                                 if (IsNaN(value))
127                                         return 0;
128                                 else
129                                         return -1;
130
131                         if (m_value > value) return 1;
132                         else if (m_value < value) return -1;
133                         else return 0;
134                 }
135
136                 public bool Equals (double value)
137                 {
138                         if (IsNaN (value)) {
139                                 if (IsNaN(m_value))
140                                         return true;
141                                 else
142                                         return false;
143                         }
144
145                         return value == m_value;
146                 }
147 #endif
148
149                 public override unsafe int GetHashCode ()
150                 {
151                         double d = m_value;
152                         return (*((long*)&d)).GetHashCode ();
153                 }
154
155                 public static bool IsInfinity (double d)
156                 {
157                         return (d == PositiveInfinity || d == NegativeInfinity);
158                 }
159
160 #if NET_2_0
161                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
162 #endif
163                 public static bool IsNaN (double d)
164                 {
165                         return (d != d);
166                 }
167
168                 public static bool IsNegativeInfinity (double d)
169                 {
170                         return (d < 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
171                 }
172
173                 public static bool IsPositiveInfinity (double d)
174                 {
175                         return (d > 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
176                 }
177
178                 public static double Parse (string s)
179                 {
180                         return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), null);
181                 }
182
183                 public static double Parse (string s, IFormatProvider fp)
184                 {
185                         return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), fp);
186                 }
187
188                 public static double Parse (string s, NumberStyles style) 
189                 {
190                         return Parse (s, style, null);
191                 }
192
193                 // We're intentionally using constants here to avoid some bigger headaches in mcs.
194                 // This struct must be compiled before System.Enum so we can't use enums here.
195                 private const int State_AllowSign = 1;
196                 private const int State_Digits = 2;
197                 private const int State_Decimal = 3;
198                 private const int State_ExponentSign = 4;
199                 private const int State_Exponent = 5;
200                 private const int State_ConsumeWhiteSpace = 6;
201                 
202                 public static double Parse (string s, NumberStyles style, IFormatProvider provider)
203                 {
204                         Exception exc;
205                         double result;
206                         
207                         if (!Parse (s, style, provider, false, out result, out exc))
208                                 throw exc;
209
210                         return result;
211                 }
212                 
213                 [MonoTODO("check if digits are group in correct numbers between the group separators")]
214                 internal static bool Parse (string s, NumberStyles style, IFormatProvider provider, bool tryParse, out double result, out Exception exc)
215                 {
216                         result = 0;
217                         exc = null;
218                         
219                         if (s == null) {
220                                 if (!tryParse)
221                                         exc = new ArgumentNullException ("s");
222                                 return false;
223                         }
224                         
225                         if (style > NumberStyles.Any) {
226                                 if (!tryParse)
227                                         exc = new ArgumentException();
228                                 return false;
229                         }
230                         
231                         NumberFormatInfo format = NumberFormatInfo.GetInstance(provider);
232                         if (format == null) throw new Exception("How did this happen?");
233                         
234                         if (s == format.NaNSymbol) {
235                                 result = Double.NaN;
236                                 return true;
237                         }
238                         if (s == format.PositiveInfinitySymbol) {
239                                 result = Double.PositiveInfinity;
240                                 return true;
241                         }
242                         if (s == format.NegativeInfinitySymbol) {
243                                 result = Double.NegativeInfinity;
244                                 return true;
245                         }
246
247                         //
248                         // validate and prepare string for C
249                         //
250                         int len = s.Length;
251                         byte [] b = new byte [len + 1];
252                         int didx = 0;
253                         int sidx = 0;
254                         char c;
255                         
256                         if ((style & NumberStyles.AllowLeadingWhite) != 0){
257                                 while (sidx < len && Char.IsWhiteSpace (c = s [sidx]))
258                                        sidx++;
259
260                                 if (sidx == len) {
261                                         if (!tryParse)
262                                                 exc = Int32.GetFormatException ();
263                                         return true;
264                                 }
265                         }
266
267                         bool allow_trailing_white = ((style & NumberStyles.AllowTrailingWhite) != 0);
268
269                         //
270                         // Machine state
271                         //
272                         int state = State_AllowSign;
273
274                         //
275                         // Setup
276                         //
277                         string decimal_separator = null;
278                         string group_separator = null;
279                         int decimal_separator_len = 0;
280                         int group_separator_len = 0;
281                         if ((style & NumberStyles.AllowDecimalPoint) != 0){
282                                 decimal_separator = format.NumberDecimalSeparator;
283                                 decimal_separator_len = decimal_separator.Length;
284                         }
285                         if ((style & NumberStyles.AllowThousands) != 0){
286                                 group_separator = format.NumberGroupSeparator;
287                                 group_separator_len = group_separator.Length;
288                         }
289                         string positive = format.PositiveSign;
290                         string negative = format.NegativeSign;
291                         
292                         for (; sidx < len; sidx++){
293                                 c = s [sidx];
294
295                                 if (c == '\0') {
296                                         sidx = len;
297                                         continue;
298                                 }
299                                 switch (state){
300                                 case State_AllowSign:
301                                         if ((style & NumberStyles.AllowLeadingSign) != 0){
302                                                 if (c == positive [0] &&
303                                                     s.Substring (sidx, positive.Length) == positive){
304                                                         state = State_Digits;
305                                                         sidx += positive.Length-1;
306                                                         continue;
307                                                 }
308
309                                                 if (c == negative [0] &&
310                                                     s.Substring (sidx, negative.Length) == negative){
311                                                         state = State_Digits;
312                                                         b [didx++] = (byte) '-';
313                                                         sidx += negative.Length-1;
314                                                         continue;
315                                                 }
316                                         }
317                                         state = State_Digits;
318                                         goto case State_Digits;
319                                         
320                                 case State_Digits:
321                                         if (Char.IsDigit (c)){
322                                                 b [didx++] = (byte) c;
323                                                 break;
324                                         }
325                                         if (c == 'e' || c == 'E')
326                                                 goto case State_Decimal;
327                                         
328                                         if (decimal_separator != null &&
329                                             decimal_separator [0] == c){
330                                                 if (s.Substring (sidx, decimal_separator_len) ==
331                                                     decimal_separator){
332                                                         b [didx++] = (byte) '.';
333                                                         sidx += decimal_separator_len-1;
334                                                         state = State_Decimal; 
335                                                         break;
336                                                 }
337                                         }
338                                         if (group_separator != null &&
339                                             group_separator [0] == c){
340                                                 if (s.Substring (sidx, group_separator_len) ==
341                                                     group_separator){
342                                                         sidx += group_separator_len-1;
343                                                         state = State_Digits; 
344                                                         break;
345                                                 }
346                                         }
347                                         
348                                         if (Char.IsWhiteSpace (c))
349                                                 goto case State_ConsumeWhiteSpace;
350
351                                         if (!tryParse)
352                                                 exc = new FormatException ("Unknown char: " + c);
353                                         return false;
354
355                                 case State_Decimal:
356                                         if (Char.IsDigit (c)){
357                                                 b [didx++] = (byte) c;
358                                                 break;
359                                         }
360
361                                         if (c == 'e' || c == 'E'){
362                                                 if ((style & NumberStyles.AllowExponent) == 0)
363                                                         throw new FormatException ("Unknown char: " + c);
364                                                 b [didx++] = (byte) c;
365                                                 state = State_ExponentSign;
366                                                 break;
367                                         }
368                                         
369                                         if (Char.IsWhiteSpace (c))
370                                                 goto case State_ConsumeWhiteSpace;
371                                         
372                                         if (!tryParse)
373                                                 exc = new FormatException ("Unknown char: " + c);
374                                         return false;
375
376                                 case State_ExponentSign:
377                                         if (Char.IsDigit (c)){
378                                                 state = State_Exponent;
379                                                 goto case State_Exponent;
380                                         }
381
382                                         if (c == positive [0] &&
383                                             s.Substring (sidx, positive.Length) == positive){
384                                                 state = State_Digits;
385                                                 sidx += positive.Length-1;
386                                                 continue;
387                                         }
388
389                                         if (c == negative [0] &&
390                                             s.Substring (sidx, negative.Length) == negative){
391                                                 state = State_Digits;
392                                                 b [didx++] = (byte) '-';
393                                                 sidx += negative.Length-1;
394                                                 continue;
395                                         }
396
397                                         if (Char.IsWhiteSpace (c))
398                                                 goto case State_ConsumeWhiteSpace;
399                                         
400                                         if (!tryParse)
401                                                 exc = new FormatException ("Unknown char: " + c);
402                                         return false;
403                                         
404                                 case State_Exponent:
405                                         if (Char.IsDigit (c)){
406                                                 b [didx++] = (byte) c;
407                                                 break;
408                                         }
409                                         
410                                         if (Char.IsWhiteSpace (c))
411                                                 goto case State_ConsumeWhiteSpace;
412                                         
413                                         if (!tryParse)
414                                                 exc = new FormatException ("Unknown char: " + c);
415                                         return false;
416
417                                 case State_ConsumeWhiteSpace:
418                                         if (allow_trailing_white && Char.IsWhiteSpace (c))
419                                                 break;
420                                         
421                                         if (!tryParse)
422                                                 exc = new FormatException ("Unknown char");
423                                         return false;
424                                 }
425                         }
426
427                         b [didx] = 0;
428                         unsafe {
429                                 fixed (byte *p = &b [0]){
430                                         double retVal;
431                                         if (!ParseImpl (p, out retVal)) {
432                                                 if (!tryParse)
433                                                         exc = Int32.GetFormatException ();
434                                                 return false;
435                                         }
436                                         if (IsPositiveInfinity(retVal) || IsNegativeInfinity(retVal)) {
437                                                 if (!tryParse)
438                                                         exc = new OverflowException ();
439                                                 return false;
440                                         }
441
442                                         result = retVal;
443                                         return true;
444                                 }
445                         }
446                 }
447
448                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
449                 unsafe private static extern bool ParseImpl (byte *byte_ptr, out double value);
450                 
451                 public static bool TryParse (string s,
452                                              NumberStyles style,
453                                              IFormatProvider provider,
454                                              out double result)
455                 {
456                         Exception exc;
457                         if (!Parse (s, style, provider, true, out result, out exc)) {
458                                 result = 0;
459                                 return false;
460                         }
461
462                         return true;
463                 }
464
465                 public override string ToString ()
466                 {
467                         return ToString (null, null);
468                 }
469
470                 public string ToString (IFormatProvider fp)
471                 {
472                         return ToString (null, fp);
473                 }
474
475                 public string ToString (string format)
476                 {
477                         return ToString (format, null);
478                 }
479
480                 public string ToString (string format, IFormatProvider fp)
481                 {
482                         NumberFormatInfo nfi = NumberFormatInfo.GetInstance (fp);
483                         return NumberFormatter.NumberToString (format, m_value, nfi);
484                 }
485
486                 // =========== IConvertible Methods =========== //
487
488                 public TypeCode GetTypeCode ()
489                 {
490                         return TypeCode.Double;
491                 }
492
493                 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
494                 {
495                         return System.Convert.ToType(m_value, conversionType, provider);
496                 }
497                 
498                 bool IConvertible.ToBoolean (IFormatProvider provider)
499                 {
500                         return System.Convert.ToBoolean(m_value);
501                 }
502                 
503                 byte IConvertible.ToByte (IFormatProvider provider)
504                 {
505                         return System.Convert.ToByte(m_value);
506                 }
507                 
508                 char IConvertible.ToChar (IFormatProvider provider)
509                 {
510                         throw new InvalidCastException();
511                 }
512                 
513                 DateTime IConvertible.ToDateTime (IFormatProvider provider)
514                 {
515                         throw new InvalidCastException();
516                 }
517                 
518                 decimal IConvertible.ToDecimal (IFormatProvider provider)
519                 {
520                         return System.Convert.ToDecimal(m_value);
521                 }
522                 
523                 double IConvertible.ToDouble (IFormatProvider provider)
524                 {
525                         return System.Convert.ToDouble(m_value);
526                 }
527                 
528                 short IConvertible.ToInt16 (IFormatProvider provider)
529                 {
530                         return System.Convert.ToInt16(m_value);
531                 }
532                 
533                 int IConvertible.ToInt32 (IFormatProvider provider)
534                 {
535                         return System.Convert.ToInt32(m_value);
536                 }
537                 
538                 long IConvertible.ToInt64 (IFormatProvider provider)
539                 {
540                         return System.Convert.ToInt64(m_value);
541                 }
542                 
543                 sbyte IConvertible.ToSByte (IFormatProvider provider)
544                 {
545                         return System.Convert.ToSByte(m_value);
546                 }
547                 
548                 float IConvertible.ToSingle (IFormatProvider provider)
549                 {
550                         return System.Convert.ToSingle(m_value);
551                 }
552                 
553 /*
554                 string IConvertible.ToString (IFormatProvider provider)
555                 {
556                         return ToString(provider);
557                 }
558 */
559
560                 ushort IConvertible.ToUInt16 (IFormatProvider provider)
561                 {
562                         return System.Convert.ToUInt16(m_value);
563                 }
564                 
565                 uint IConvertible.ToUInt32 (IFormatProvider provider)
566                 {
567                         return System.Convert.ToUInt32(m_value);
568                 }
569                 
570                 ulong IConvertible.ToUInt64 (IFormatProvider provider)
571                 {
572                         return System.Convert.ToUInt64(m_value);
573                 }
574         }
575 }