remove warning
[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 #if NET_2_0
46         [System.Runtime.InteropServices.ComVisible (true)]
47 #endif
48         public struct Double : IComparable, IFormattable, IConvertible
49 #if NET_2_0
50                 , IComparable <double>, IEquatable <double>
51 #endif
52         {
53                 public const double Epsilon = 4.9406564584124650e-324;
54                 public const double MaxValue =  1.7976931348623157e308;
55                 public const double MinValue = -1.7976931348623157e308;
56                 public const double NaN = 0.0d / 0.0d;
57                 public const double NegativeInfinity = -1.0d / 0.0d;
58                 public const double PositiveInfinity = 1.0d / 0.0d;
59                 
60                 internal double m_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 #pragma warning disable 1718
166                         return (d != d);
167 #pragma warning restore
168                 }
169
170                 public static bool IsNegativeInfinity (double d)
171                 {
172                         return (d < 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
173                 }
174
175                 public static bool IsPositiveInfinity (double d)
176                 {
177                         return (d > 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
178                 }
179
180                 public static double Parse (string s)
181                 {
182                         return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), null);
183                 }
184
185                 public static double Parse (string s, IFormatProvider fp)
186                 {
187                         return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), fp);
188                 }
189
190                 public static double Parse (string s, NumberStyles style) 
191                 {
192                         return Parse (s, style, null);
193                 }
194
195                 // We're intentionally using constants here to avoid some bigger headaches in mcs.
196                 // This struct must be compiled before System.Enum so we can't use enums here.
197                 private const int State_AllowSign = 1;
198                 private const int State_Digits = 2;
199                 private const int State_Decimal = 3;
200                 private const int State_ExponentSign = 4;
201                 private const int State_Exponent = 5;
202                 private const int State_ConsumeWhiteSpace = 6;
203                 private const int State_Exit = 7;
204                 
205                 public static double Parse (string s, NumberStyles style, IFormatProvider provider)
206                 {
207                         Exception exc;
208                         double result;
209                         
210                         if (!Parse (s, style, provider, false, out result, out exc))
211                                 throw exc;
212
213                         return result;
214                 }
215                 
216                 // FIXME: check if digits are group in correct numbers between the group separators
217                 internal static bool Parse (string s, NumberStyles style, IFormatProvider provider, bool tryParse, out double result, out Exception exc)
218                 {
219                         result = 0;
220                         exc = null;
221                         
222                         if (s == null) {
223                                 if (!tryParse)
224                                         exc = new ArgumentNullException ("s");
225                                 return false;
226                         }
227                         if (s.Length == 0) {
228                                 if (!tryParse)
229                                         exc = new FormatException ();
230                                 return false;
231                         }
232 #if NET_2_0
233                         // yes it's counter intuitive (buggy?) but even TryParse actually throws in this case
234                         if ((style & NumberStyles.AllowHexSpecifier) != 0) {
235                                 string msg = Locale.GetText ("Double doesn't support parsing with '{0}'.", "AllowHexSpecifier");
236                                 throw new ArgumentException (msg);
237                         }
238 #endif
239                         if (style > NumberStyles.Any) {
240                                 if (!tryParse)
241                                         exc = new ArgumentException();
242                                 return false;
243                         }
244
245                         NumberFormatInfo format = NumberFormatInfo.GetInstance(provider);
246                         if (format == null) throw new Exception("How did this happen?");
247                         
248                         if (s == format.NaNSymbol) {
249                                 result = Double.NaN;
250                                 return true;
251                         }
252                         if (s == format.PositiveInfinitySymbol) {
253                                 result = Double.PositiveInfinity;
254                                 return true;
255                         }
256                         if (s == format.NegativeInfinitySymbol) {
257                                 result = Double.NegativeInfinity;
258                                 return true;
259                         }
260
261                         //
262                         // validate and prepare string for C
263                         //
264                         int len = s.Length;
265                         byte [] b = new byte [len + 1];
266                         int didx = 0;
267                         int sidx = 0;
268                         char c;
269                         
270                         if ((style & NumberStyles.AllowLeadingWhite) != 0){
271                                 while (sidx < len && Char.IsWhiteSpace (c = s [sidx]))
272                                        sidx++;
273
274                                 if (sidx == len) {
275                                         if (!tryParse)
276                                                 exc = Int32.GetFormatException ();
277                                         return false;
278                                 }
279                         }
280
281                         bool allow_trailing_white = ((style & NumberStyles.AllowTrailingWhite) != 0);
282
283                         //
284                         // Machine state
285                         //
286                         int state = State_AllowSign;
287
288                         //
289                         // Setup
290                         //
291                         string decimal_separator = null;
292                         string group_separator = null;
293                         string currency_symbol = null;
294                         int decimal_separator_len = 0;
295                         int group_separator_len = 0;
296                         int currency_symbol_len = 0;
297                         if ((style & NumberStyles.AllowDecimalPoint) != 0){
298                                 decimal_separator = format.NumberDecimalSeparator;
299                                 decimal_separator_len = decimal_separator.Length;
300                         }
301                         if ((style & NumberStyles.AllowThousands) != 0){
302                                 group_separator = format.NumberGroupSeparator;
303                                 group_separator_len = group_separator.Length;
304                         }
305                         if ((style & NumberStyles.AllowCurrencySymbol) != 0){
306                                 currency_symbol = format.CurrencySymbol;
307                                 currency_symbol_len = currency_symbol.Length;
308                         }
309                         string positive = format.PositiveSign;
310                         string negative = format.NegativeSign;
311                         
312                         for (; sidx < len; sidx++){
313                                 c = s [sidx];
314
315                                 if (c == '\0') {
316                                         sidx = len;
317                                         continue;
318                                 }
319
320                                 switch (state){
321                                 case State_AllowSign:
322                                         if ((style & NumberStyles.AllowLeadingSign) != 0){
323                                                 if (c == positive [0] &&
324                                                     s.Substring (sidx, positive.Length) == positive){
325                                                         state = State_Digits;
326                                                         sidx += positive.Length-1;
327                                                         continue;
328                                                 }
329
330                                                 if (c == negative [0] &&
331                                                     s.Substring (sidx, negative.Length) == negative){
332                                                         state = State_Digits;
333                                                         b [didx++] = (byte) '-';
334                                                         sidx += negative.Length-1;
335                                                         continue;
336                                                 }
337                                         }
338                                         state = State_Digits;
339                                         goto case State_Digits;
340                                         
341                                 case State_Digits:
342                                         if (Char.IsDigit (c)){
343                                                 b [didx++] = (byte) c;
344                                                 break;
345                                         }
346                                         if (c == 'e' || c == 'E')
347                                                 goto case State_Decimal;
348                                         
349                                         if (decimal_separator != null &&
350                                             decimal_separator [0] == c) {
351                                                 if (String.CompareOrdinal (s, sidx, decimal_separator, 0, decimal_separator_len) == 0) {
352                                                         b [didx++] = (byte) '.';
353                                                         sidx += decimal_separator_len-1;
354                                                         state = State_Decimal; 
355                                                         break;
356                                                 }
357                                         }
358                                         if (group_separator != null &&
359                                             group_separator [0] == c){
360                                                 if (s.Substring (sidx, group_separator_len) ==
361                                                     group_separator){
362                                                         sidx += group_separator_len-1;
363                                                         state = State_Digits; 
364                                                         break;
365                                                 }
366                                         }
367                                         if (currency_symbol != null &&
368                                             currency_symbol [0] == c){
369                                                 if (s.Substring (sidx, currency_symbol_len) ==
370                                                     currency_symbol){
371                                                         sidx += currency_symbol_len-1;
372                                                         state = State_Digits; 
373                                                         break;
374                                                 }
375                                         }
376                                         
377                                         if (Char.IsWhiteSpace (c))
378                                                 goto case State_ConsumeWhiteSpace;
379
380                                         if (!tryParse)
381                                                 exc = new FormatException ("Unknown char: " + c);
382                                         return false;
383
384                                 case State_Decimal:
385                                         if (Char.IsDigit (c)){
386                                                 b [didx++] = (byte) c;
387                                                 break;
388                                         }
389
390                                         if (c == 'e' || c == 'E'){
391                                                 if ((style & NumberStyles.AllowExponent) == 0) {
392                                                         if (!tryParse)
393                                                                 exc = new FormatException ("Unknown char: " + c);
394                                                         return false;
395                                                 }
396                                                 b [didx++] = (byte) c;
397                                                 state = State_ExponentSign;
398                                                 break;
399                                         }
400                                         
401                                         if (Char.IsWhiteSpace (c))
402                                                 goto case State_ConsumeWhiteSpace;
403                                         
404                                         if (!tryParse)
405                                                 exc = new FormatException ("Unknown char: " + c);
406                                         return false;
407
408                                 case State_ExponentSign:
409                                         if (Char.IsDigit (c)){
410                                                 state = State_Exponent;
411                                                 goto case State_Exponent;
412                                         }
413
414                                         if (c == positive [0] &&
415                                             s.Substring (sidx, positive.Length) == positive){
416                                                 state = State_Digits;
417                                                 sidx += positive.Length-1;
418                                                 continue;
419                                         }
420
421                                         if (c == negative [0] &&
422                                             s.Substring (sidx, negative.Length) == negative){
423                                                 state = State_Digits;
424                                                 b [didx++] = (byte) '-';
425                                                 sidx += negative.Length-1;
426                                                 continue;
427                                         }
428
429                                         if (Char.IsWhiteSpace (c))
430                                                 goto case State_ConsumeWhiteSpace;
431                                         
432                                         if (!tryParse)
433                                                 exc = new FormatException ("Unknown char: " + c);
434                                         return false;
435                                         
436                                 case State_Exponent:
437                                         if (Char.IsDigit (c)){
438                                                 b [didx++] = (byte) c;
439                                                 break;
440                                         }
441                                         
442                                         if (Char.IsWhiteSpace (c))
443                                                 goto case State_ConsumeWhiteSpace;
444                                         
445                                         if (!tryParse)
446                                                 exc = new FormatException ("Unknown char: " + c);
447                                         return false;
448
449                                 case State_ConsumeWhiteSpace:
450                                         if (allow_trailing_white && Char.IsWhiteSpace (c)) {
451                                                 state = State_ConsumeWhiteSpace;
452                                                 break;
453                                         }
454                                         
455                                         if (!tryParse)
456                                                 exc = new FormatException ("Unknown char");
457                                         return false;
458                                 }
459
460                                 if (state == State_Exit)
461                                         break;
462                         }
463
464                         b [didx] = 0;
465                         unsafe {
466                                 fixed (byte *p = &b [0]){
467                                         double retVal;
468                                         if (!ParseImpl (p, out retVal)) {
469                                                 if (!tryParse)
470                                                         exc = Int32.GetFormatException ();
471                                                 return false;
472                                         }
473                                         if (IsPositiveInfinity(retVal) || IsNegativeInfinity(retVal)) {
474                                                 if (!tryParse)
475                                                         exc = new OverflowException ();
476                                                 return false;
477                                         }
478
479                                         result = retVal;
480                                         return true;
481                                 }
482                         }
483                 }
484
485                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
486                 unsafe private static extern bool ParseImpl (byte *byte_ptr, out double value);
487                 
488                 public static bool TryParse (string s,
489                                              NumberStyles style,
490                                              IFormatProvider provider,
491                                              out double result)
492                 {
493                         Exception exc;
494                         if (!Parse (s, style, provider, true, out result, out exc)) {
495                                 result = 0;
496                                 return false;
497                         }
498
499                         return true;
500                 }
501 #if NET_2_0
502                 public static bool TryParse (string s, out double result)
503                 {
504                         return TryParse (s, NumberStyles.Any, null, out result);
505                 }
506 #endif
507                 public override string ToString ()
508                 {
509                         return ToString (null, null);
510                 }
511
512                 public string ToString (IFormatProvider fp)
513                 {
514                         return ToString (null, fp);
515                 }
516
517                 public string ToString (string format)
518                 {
519                         return ToString (format, null);
520                 }
521
522                 public string ToString (string format, IFormatProvider fp)
523                 {
524                         NumberFormatInfo nfi = NumberFormatInfo.GetInstance (fp);
525                         return NumberFormatter.NumberToString (format, m_value, nfi);
526                 }
527
528                 // =========== IConvertible Methods =========== //
529
530                 public TypeCode GetTypeCode ()
531                 {
532                         return TypeCode.Double;
533                 }
534
535                 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
536                 {
537                         return System.Convert.ToType(m_value, conversionType, provider);
538                 }
539                 
540                 bool IConvertible.ToBoolean (IFormatProvider provider)
541                 {
542                         return System.Convert.ToBoolean(m_value);
543                 }
544                 
545                 byte IConvertible.ToByte (IFormatProvider provider)
546                 {
547                         return System.Convert.ToByte(m_value);
548                 }
549                 
550                 char IConvertible.ToChar (IFormatProvider provider)
551                 {
552                         throw new InvalidCastException();
553                 }
554                 
555                 DateTime IConvertible.ToDateTime (IFormatProvider provider)
556                 {
557                         throw new InvalidCastException();
558                 }
559                 
560                 decimal IConvertible.ToDecimal (IFormatProvider provider)
561                 {
562                         return System.Convert.ToDecimal(m_value);
563                 }
564                 
565                 double IConvertible.ToDouble (IFormatProvider provider)
566                 {
567                         return System.Convert.ToDouble(m_value);
568                 }
569                 
570                 short IConvertible.ToInt16 (IFormatProvider provider)
571                 {
572                         return System.Convert.ToInt16(m_value);
573                 }
574                 
575                 int IConvertible.ToInt32 (IFormatProvider provider)
576                 {
577                         return System.Convert.ToInt32(m_value);
578                 }
579                 
580                 long IConvertible.ToInt64 (IFormatProvider provider)
581                 {
582                         return System.Convert.ToInt64(m_value);
583                 }
584                 
585                 sbyte IConvertible.ToSByte (IFormatProvider provider)
586                 {
587                         return System.Convert.ToSByte(m_value);
588                 }
589                 
590                 float IConvertible.ToSingle (IFormatProvider provider)
591                 {
592                         return System.Convert.ToSingle(m_value);
593                 }
594                 
595 /*
596                 string IConvertible.ToString (IFormatProvider provider)
597                 {
598                         return ToString(provider);
599                 }
600 */
601
602                 ushort IConvertible.ToUInt16 (IFormatProvider provider)
603                 {
604                         return System.Convert.ToUInt16(m_value);
605                 }
606                 
607                 uint IConvertible.ToUInt32 (IFormatProvider provider)
608                 {
609                         return System.Convert.ToUInt32(m_value);
610                 }
611                 
612                 ulong IConvertible.ToUInt64 (IFormatProvider provider)
613                 {
614                         return System.Convert.ToUInt64(m_value);
615                 }
616         }
617 }