2010-04-07 Jb Evain <jbevain@novell.com>
[mcs.git] / class / corlib / System / Double.cs
blob53aa6389f9974e284bbf478bb3b3f96478115d8a
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
13 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
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.
35 using System.Globalization;
36 using System.Runtime.CompilerServices;
37 using System.Runtime.ConstrainedExecution;
39 namespace System {
41 [Serializable]
42 [System.Runtime.InteropServices.ComVisible (true)]
43 public struct Double : IComparable, IFormattable, IConvertible, IComparable <double>, IEquatable <double>
45 public const double Epsilon = 4.9406564584124650e-324;
46 public const double MaxValue = 1.7976931348623157e308;
47 public const double MinValue = -1.7976931348623157e308;
48 public const double NaN = 0.0d / 0.0d;
49 public const double NegativeInfinity = -1.0d / 0.0d;
50 public const double PositiveInfinity = 1.0d / 0.0d;
52 internal double m_value;
54 public int CompareTo (object value)
56 if (value == null)
57 return 1;
59 if (!(value is System.Double))
60 throw new ArgumentException (Locale.GetText ("Value is not a System.Double"));
62 double dv = (double)value;
64 if (IsPositiveInfinity(m_value) && IsPositiveInfinity(dv))
65 return 0;
67 if (IsNegativeInfinity(m_value) && IsNegativeInfinity(dv))
68 return 0;
70 if (IsNaN(dv))
71 if (IsNaN(m_value))
72 return 0;
73 else
74 return 1;
76 if (IsNaN(m_value))
77 if (IsNaN(dv))
78 return 0;
79 else
80 return -1;
82 if (m_value > dv) return 1;
83 else if (m_value < dv) return -1;
84 else return 0;
87 public override bool Equals (object obj)
89 if (!(obj is System.Double))
90 return false;
92 double value = (double) obj;
94 if (IsNaN (value))
95 return IsNaN (m_value);
97 return (value == m_value);
100 public int CompareTo (double value)
102 if (IsPositiveInfinity(m_value) && IsPositiveInfinity(value))
103 return 0;
105 if (IsNegativeInfinity(m_value) && IsNegativeInfinity(value))
106 return 0;
108 if (IsNaN(value))
109 if (IsNaN(m_value))
110 return 0;
111 else
112 return 1;
114 if (IsNaN(m_value))
115 if (IsNaN(value))
116 return 0;
117 else
118 return -1;
120 if (m_value > value) return 1;
121 else if (m_value < value) return -1;
122 else return 0;
125 public bool Equals (double obj)
127 if (IsNaN (obj)) {
128 if (IsNaN(m_value))
129 return true;
130 else
131 return false;
134 return obj == m_value;
137 public override unsafe int GetHashCode ()
139 double d = m_value;
140 return (*((long*)&d)).GetHashCode ();
143 #if NET_4_0
144 public static bool operator==(double a, double b)
146 return a == b;
149 public static bool operator!=(double a, double b)
151 return a != b;
154 public static bool operator>(double a, double b)
156 return a > b;
159 public static bool operator>=(double a, double b)
161 return a >= b;
164 public static bool operator<(double a, double b)
166 return a < b;
169 public static bool operator<=(double a, double b)
171 return a <= b;
173 #endif
175 public static bool IsInfinity (double d)
177 return (d == PositiveInfinity || d == NegativeInfinity);
180 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
181 public static bool IsNaN (double d)
183 #pragma warning disable 1718
184 return (d != d);
185 #pragma warning restore
188 public static bool IsNegativeInfinity (double d)
190 return (d < 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
193 public static bool IsPositiveInfinity (double d)
195 return (d > 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
198 public static double Parse (string s)
200 return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), null);
203 public static double Parse (string s, IFormatProvider provider)
205 return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), provider);
208 public static double Parse (string s, NumberStyles style)
210 return Parse (s, style, null);
213 // We're intentionally using constants here to avoid some bigger headaches in mcs.
214 // This struct must be compiled before System.Enum so we can't use enums here.
215 private const int State_AllowSign = 1;
216 private const int State_Digits = 2;
217 private const int State_Decimal = 3;
218 private const int State_ExponentSign = 4;
219 private const int State_Exponent = 5;
220 private const int State_ConsumeWhiteSpace = 6;
221 private const int State_Exit = 7;
223 public static double Parse (string s, NumberStyles style, IFormatProvider provider)
225 Exception exc;
226 double result;
228 if (!Parse (s, style, provider, false, out result, out exc))
229 throw exc;
231 return result;
234 // FIXME: check if digits are group in correct numbers between the group separators
235 internal static bool Parse (string s, NumberStyles style, IFormatProvider provider, bool tryParse, out double result, out Exception exc)
237 result = 0;
238 exc = null;
240 if (s == null) {
241 if (!tryParse)
242 exc = new ArgumentNullException ("s");
243 return false;
245 if (s.Length == 0) {
246 if (!tryParse)
247 exc = new FormatException ();
248 return false;
250 // yes it's counter intuitive (buggy?) but even TryParse actually throws in this case
251 if ((style & NumberStyles.AllowHexSpecifier) != 0) {
252 string msg = Locale.GetText ("Double doesn't support parsing with '{0}'.", "AllowHexSpecifier");
253 throw new ArgumentException (msg);
255 if (style > NumberStyles.Any) {
256 if (!tryParse)
257 exc = new ArgumentException();
258 return false;
261 NumberFormatInfo format = NumberFormatInfo.GetInstance(provider);
262 if (format == null) throw new Exception("How did this happen?");
265 // validate and prepare string for C
267 int len = s.Length;
268 int didx = 0;
269 int sidx = 0;
270 char c;
271 bool allow_leading_white = (style & NumberStyles.AllowLeadingWhite) != 0;
272 bool allow_trailing_white = ((style & NumberStyles.AllowTrailingWhite) != 0);
274 if (allow_leading_white) {
275 while (sidx < len && Char.IsWhiteSpace (s [sidx]))
276 sidx++;
278 if (sidx == len) {
279 if (!tryParse)
280 exc = Int32.GetFormatException ();
281 return false;
284 int sEndPos = s.Length - 1;
285 if (allow_trailing_white)
286 while (Char.IsWhiteSpace (s [sEndPos]))
287 sEndPos--;
289 if (TryParseStringConstant (format.NaNSymbol, s, sidx, sEndPos)) {
290 result = double.NaN;
291 return true;
293 if (TryParseStringConstant (format.PositiveInfinitySymbol, s, sidx, sEndPos)) {
294 result = double.PositiveInfinity;
295 return true;
297 if (TryParseStringConstant (format.NegativeInfinitySymbol, s, sidx, sEndPos)) {
298 result = double.NegativeInfinity;
299 return true;
302 byte [] b = new byte [len + 1];
305 // Machine state
307 int state = State_AllowSign;
310 // Setup
312 string decimal_separator = null;
313 string group_separator = null;
314 string currency_symbol = null;
315 int decimal_separator_len = 0;
316 int group_separator_len = 0;
317 int currency_symbol_len = 0;
318 if ((style & NumberStyles.AllowDecimalPoint) != 0){
319 decimal_separator = format.NumberDecimalSeparator;
320 decimal_separator_len = decimal_separator.Length;
322 if ((style & NumberStyles.AllowThousands) != 0){
323 group_separator = format.NumberGroupSeparator;
324 group_separator_len = group_separator.Length;
326 if ((style & NumberStyles.AllowCurrencySymbol) != 0){
327 currency_symbol = format.CurrencySymbol;
328 currency_symbol_len = currency_symbol.Length;
330 string positive = format.PositiveSign;
331 string negative = format.NegativeSign;
333 for (; sidx < len; sidx++){
334 c = s [sidx];
336 if (c == '\0') {
337 sidx = len;
338 continue;
341 switch (state){
342 case State_AllowSign:
343 if ((style & NumberStyles.AllowLeadingSign) != 0){
344 if (c == positive [0] &&
345 s.Substring (sidx, positive.Length) == positive){
346 state = State_Digits;
347 sidx += positive.Length-1;
348 continue;
351 if (c == negative [0] &&
352 s.Substring (sidx, negative.Length) == negative){
353 state = State_Digits;
354 b [didx++] = (byte) '-';
355 sidx += negative.Length-1;
356 continue;
359 state = State_Digits;
360 goto case State_Digits;
362 case State_Digits:
363 if (Char.IsDigit (c)){
364 b [didx++] = (byte) c;
365 break;
367 if (c == 'e' || c == 'E')
368 goto case State_Decimal;
370 if (decimal_separator_len > 0 &&
371 decimal_separator [0] == c) {
372 if (String.CompareOrdinal (s, sidx, decimal_separator, 0, decimal_separator_len) == 0) {
373 b [didx++] = (byte) '.';
374 sidx += decimal_separator_len-1;
375 state = State_Decimal;
376 break;
379 if (group_separator_len > 0 &&
380 group_separator [0] == c){
381 if (s.Substring (sidx, group_separator_len) ==
382 group_separator){
383 sidx += group_separator_len-1;
384 state = State_Digits;
385 break;
388 if (currency_symbol_len > 0 &&
389 currency_symbol [0] == c){
390 if (s.Substring (sidx, currency_symbol_len) ==
391 currency_symbol){
392 sidx += currency_symbol_len-1;
393 state = State_Digits;
394 break;
398 if (Char.IsWhiteSpace (c))
399 goto case State_ConsumeWhiteSpace;
401 if (!tryParse)
402 exc = new FormatException ("Unknown char: " + c);
403 return false;
405 case State_Decimal:
406 if (Char.IsDigit (c)){
407 b [didx++] = (byte) c;
408 break;
411 if (c == 'e' || c == 'E'){
412 if ((style & NumberStyles.AllowExponent) == 0) {
413 if (!tryParse)
414 exc = new FormatException ("Unknown char: " + c);
415 return false;
417 b [didx++] = (byte) c;
418 state = State_ExponentSign;
419 break;
422 if (Char.IsWhiteSpace (c))
423 goto case State_ConsumeWhiteSpace;
425 if (!tryParse)
426 exc = new FormatException ("Unknown char: " + c);
427 return false;
429 case State_ExponentSign:
430 if (Char.IsDigit (c)){
431 state = State_Exponent;
432 goto case State_Exponent;
435 if (c == positive [0] &&
436 s.Substring (sidx, positive.Length) == positive){
437 state = State_Digits;
438 sidx += positive.Length-1;
439 continue;
442 if (c == negative [0] &&
443 s.Substring (sidx, negative.Length) == negative){
444 state = State_Digits;
445 b [didx++] = (byte) '-';
446 sidx += negative.Length-1;
447 continue;
450 if (Char.IsWhiteSpace (c))
451 goto case State_ConsumeWhiteSpace;
453 if (!tryParse)
454 exc = new FormatException ("Unknown char: " + c);
455 return false;
457 case State_Exponent:
458 if (Char.IsDigit (c)){
459 b [didx++] = (byte) c;
460 break;
463 if (Char.IsWhiteSpace (c))
464 goto case State_ConsumeWhiteSpace;
466 if (!tryParse)
467 exc = new FormatException ("Unknown char: " + c);
468 return false;
470 case State_ConsumeWhiteSpace:
471 if (allow_trailing_white && Char.IsWhiteSpace (c)) {
472 state = State_ConsumeWhiteSpace;
473 break;
476 if (!tryParse)
477 exc = new FormatException ("Unknown char");
478 return false;
481 if (state == State_Exit)
482 break;
485 b [didx] = 0;
486 unsafe {
487 fixed (byte *p = &b [0]){
488 double retVal;
489 if (!ParseImpl (p, out retVal)) {
490 if (!tryParse)
491 exc = Int32.GetFormatException ();
492 return false;
494 if (IsPositiveInfinity(retVal) || IsNegativeInfinity(retVal)) {
495 if (!tryParse)
496 exc = new OverflowException ();
497 return false;
500 result = retVal;
501 return true;
506 static bool TryParseStringConstant (string format, string s, int start, int end)
508 return end - start + 1 == format.Length && String.CompareOrdinal (format, 0, s, start, format.Length) == 0;
511 [MethodImplAttribute(MethodImplOptions.InternalCall)]
512 unsafe private static extern bool ParseImpl (byte *byte_ptr, out double value);
514 public static bool TryParse (string s,
515 NumberStyles style,
516 IFormatProvider provider,
517 out double result)
519 Exception exc;
520 if (!Parse (s, style, provider, true, out result, out exc)) {
521 result = 0;
522 return false;
525 return true;
528 public static bool TryParse (string s, out double result)
530 return TryParse (s, NumberStyles.Any, null, out result);
533 public override string ToString ()
535 return NumberFormatter.NumberToString (m_value, null);
538 public string ToString (IFormatProvider provider)
540 return NumberFormatter.NumberToString (m_value, provider);
543 public string ToString (string format)
545 return ToString (format, null);
548 public string ToString (string format, IFormatProvider provider)
550 return NumberFormatter.NumberToString (format, m_value, provider);
553 // =========== IConvertible Methods =========== //
555 public TypeCode GetTypeCode ()
557 return TypeCode.Double;
560 object IConvertible.ToType (Type targetType, IFormatProvider provider)
562 if (targetType == null)
563 throw new ArgumentNullException ("targetType");
564 return System.Convert.ToType (m_value, targetType, provider, false);
567 bool IConvertible.ToBoolean (IFormatProvider provider)
569 return System.Convert.ToBoolean (m_value);
572 byte IConvertible.ToByte (IFormatProvider provider)
574 return System.Convert.ToByte (m_value);
577 char IConvertible.ToChar (IFormatProvider provider)
579 throw new InvalidCastException ();
582 DateTime IConvertible.ToDateTime (IFormatProvider provider)
584 throw new InvalidCastException ();
587 decimal IConvertible.ToDecimal (IFormatProvider provider)
589 return System.Convert.ToDecimal (m_value);
592 double IConvertible.ToDouble (IFormatProvider provider)
594 return System.Convert.ToDouble (m_value);
597 short IConvertible.ToInt16 (IFormatProvider provider)
599 return System.Convert.ToInt16 (m_value);
602 int IConvertible.ToInt32 (IFormatProvider provider)
604 return System.Convert.ToInt32 (m_value);
607 long IConvertible.ToInt64 (IFormatProvider provider)
609 return System.Convert.ToInt64 (m_value);
612 sbyte IConvertible.ToSByte (IFormatProvider provider)
614 return System.Convert.ToSByte (m_value);
617 float IConvertible.ToSingle (IFormatProvider provider)
619 return System.Convert.ToSingle (m_value);
622 ushort IConvertible.ToUInt16 (IFormatProvider provider)
624 return System.Convert.ToUInt16 (m_value);
626 uint IConvertible.ToUInt32 (IFormatProvider provider)
628 return System.Convert.ToUInt32 (m_value);
630 ulong IConvertible.ToUInt64 (IFormatProvider provider)
632 return System.Convert.ToUInt64 (m_value);